基於阿里egg框架搭建博客(4)——權限控制

相關文章

基於阿里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.*']
            }
        }

結尾

如果看完覺得有用,請給作者一個喜歡吧!謝謝啦!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章