1

相关文章

基于阿里egg框架搭建博客(1)——开发准备
基于阿里egg框架搭建博客(2)——Hello World
基于阿里egg框架搭建博客(3)——注册与登录
基于阿里egg框架搭建博客(4)——权限控制
基于阿里egg框架搭建博客(5)——置顶导航条
基于阿里egg框架搭建博客(6)——浏览、发表文章
基于阿里egg框架搭建博客(7)——编辑文章

git

https://github.com/ZzzSimon/e...
喜欢就点个赞吧!

正文

上一篇文章我们实现了用户的注册与登录,接下来就需要对用户权限进行控制了,比如:普通用户只能评论,管理员可以发表文章,最高管理员可以修改用户权限等等。
由于权限控制是一个通用的功能,我们把这块功能做成中间件。关于中间件:

官方文档:https://eggjs.org/zh-cn/basic...

功能设计

  1. 一个用户对应1个角色
  2. 可以通过配置文件配置,某一个角色无权限使用的页面与接口
  3. 可以配置无需验证用户与权限的path。比如:登录与注册的相关页面与接口
  4. 只有登录过才能访问的path,否则跳转登录页。

User表,增加role(角色)字段

配置文件

我们在config/config.default.js中加入以下内容:

        auth : {
            noAuth:['/login.htm','/user/login','/register.htm','/user/register'],
            noPermission:{
                admin:[],
                manager:['/admin.htm'],
                user:['/admin.htm','/edit.htm']
            }
        }

其中:
noAuth节点配置的是无需验权就能访问的path
noPermission节点配置的是各个角色无权限访问的path

auth.js中间件代码

我们创建app/middleware/auth.js文件:

module.exports = (options, app) => {
    return async function auth(ctx, next) {
        //如果用户session没失效
        if (typeof (ctx.session.user) !== 'undefined') {
            const username = ctx.session.user.username;
            //这里有两种做法,第一种每次都查库校验角色,优点:实时,角色变更对用户无感。缺点:查库效率低,可考虑用redis
            //第二种,把角色信息放进session,优点:无需查库,效率高。缺点:角色变更时需额外逻辑来处理老的session,否则客户端的用户角色无法实时更新
            const role = await ctx.service.user.getRoleByUsername(username);
            const noPerList = options.noPermission[role];
            if (noPerList && !noPerList.includes(ctx.path)) {
                await next();
            } else {
                ctx.body = '无权限,请联系网站管理员!';
            }
            //登录注册页面不需要权限
        } else if (options.noAuth.includes(ctx.path)) {
            await next();
            //如果session失效后则重定向到登录页
        } else {
            ctx.redirect('/login.htm')
        }
    }
};

效果

我们创建一个用户,并给与他user角色,由配置文件可以看出,user角色无权限访问/edit.htm路径。如图:

正则匹配

如果页面也来越多,或者有些带参数的path是动态的,我们需要一定的规则来过滤path。这时候就需要用到正则匹配,我们修改auth.js文件:

module.exports = (options, app) => {
    function isNoPer(noPerList,path) {
        for (let i = 0;i<noPerList.length;i++){
            const patt=new RegExp(noPerList[i]);
            if (patt.test(path)) {
                return true;
            }
        }
        return false;
    }
    return async function auth(ctx, next) {
        //如果用户session没失效
        if (typeof (ctx.session.user) !== 'undefined') {
            const username = ctx.session.user.username;
            //这里有两种做法,第一种每次都查库校验角色,优点:实时,角色变更对用户无感。缺点:查库效率低,可考虑用redis
            //第二种,把角色信息放进session,优点:无需查库,效率高。缺点:角色变更时需额外逻辑来处理老的session,否则客户端的用户角色无法实时更新
            const role = await ctx.service.user.getRoleByUsername(username);
            const noPerList = options.noPermission[role];
            if (noPerList && !isNoPer(noPerList,ctx.path)) {
                await next();
            } else {
                ctx.body = '无权限,请联系网站管理员!';
            }
            //登录注册页面不需要权限
        } else if (options.noAuth.includes(ctx.path)) {
            await next();
            //如果session失效后则重定向到登录页
        } else {
            ctx.redirect('/login.htm')
        }
    }
};

这时候我们的配置文件就可以支持正则表达式了:

        auth : {
            noAuth:['/login.htm','/user/login','/register.htm','/user/register'],
            noPermission:{
                admin:[],
                manager:['/admin.htm'],
                user:['/admin.htm','/edit.*']
            }
        }

结尾

如果看完觉得有用,请给作者一个喜欢吧!谢谢啦!


妖云小离
38 声望1 粉丝

好想当个太空人,这样的话只要我质量够大,你们都得围着我转~~