相關(guān)文章
基于阿里egg框架搭建博客(1)——開發(fā)準(zhǔn)備
基于阿里egg框架搭建博客(2)——Hello World
基于阿里egg框架搭建博客(3)——注冊與登錄
基于阿里egg框架搭建博客(4)——權(quán)限控制
基于阿里egg框架搭建博客(5)——置頂導(dǎo)航條
基于阿里egg框架搭建博客(6)——瀏覽、發(fā)表文章
基于阿里egg框架搭建博客(7)——編輯文章
git
https://github.com/ZzzSimon/egg-example
喜歡就點(diǎn)個(gè)贊吧!
正文
上一篇文章我們實(shí)現(xiàn)了用戶的注冊與登錄,接下來就需要對用戶權(quán)限進(jìn)行控制了,比如:普通用戶只能評(píng)論,管理員可以發(fā)表文章,最高管理員可以修改用戶權(quán)限等等。
由于權(quán)限控制是一個(gè)通用的功能,我們把這塊功能做成中間件。關(guān)于中間件:
功能設(shè)計(jì)
- 一個(gè)用戶對應(yīng)1個(gè)角色
- 可以通過配置文件配置,某一個(gè)角色無權(quán)限使用的頁面與接口
- 可以配置無需驗(yàn)證用戶與權(quán)限的path。比如:登錄與注冊的相關(guān)頁面與接口
- 只有登錄過才能訪問的path,否則跳轉(zhuǎn)登錄頁。
User表,增加role(角色)字段

配置文件
我們在config/config.default.js中加入以下內(nèi)容:
auth : {
noAuth:['/login.htm','/user/login','/register.htm','/user/register'],
noPermission:{
admin:[],
manager:['/admin.htm'],
user:['/admin.htm','/edit.htm']
}
}
其中:
noAuth節(jié)點(diǎn)配置的是無需驗(yàn)權(quán)就能訪問的path
noPermission節(jié)點(diǎn)配置的是各個(gè)角色無權(quán)限訪問的path
auth.js中間件代碼
我們創(chuàng)建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;
//這里有兩種做法,第一種每次都查庫校驗(yàn)角色,優(yōu)點(diǎn):實(shí)時(shí),角色變更對用戶無感。缺點(diǎn):查庫效率低,可考慮用redis
//第二種,把角色信息放進(jìn)session,優(yōu)點(diǎn):無需查庫,效率高。缺點(diǎn):角色變更時(shí)需額外邏輯來處理老的session,否則客戶端的用戶角色無法實(shí)時(shí)更新
const role = await ctx.service.user.getRoleByUsername(username);
const noPerList = options.noPermission[role];
if (noPerList && !noPerList.includes(ctx.path)) {
await next();
} else {
ctx.body = '無權(quán)限,請聯(lián)系網(wǎng)站管理員!';
}
//登錄注冊頁面不需要權(quán)限
} else if (options.noAuth.includes(ctx.path)) {
await next();
//如果session失效后則重定向到登錄頁
} else {
ctx.redirect('/login.htm')
}
}
};
效果
我們創(chuàng)建一個(gè)用戶,并給與他user角色,由配置文件可以看出,user角色無權(quán)限訪問/edit.htm路徑。如圖:

正則匹配
如果頁面也來越多,或者有些帶參數(shù)的path是動(dòng)態(tài)的,我們需要一定的規(guī)則來過濾path。這時(shí)候就需要用到正則匹配,我們修改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;
//這里有兩種做法,第一種每次都查庫校驗(yàn)角色,優(yōu)點(diǎn):實(shí)時(shí),角色變更對用戶無感。缺點(diǎn):查庫效率低,可考慮用redis
//第二種,把角色信息放進(jìn)session,優(yōu)點(diǎn):無需查庫,效率高。缺點(diǎn):角色變更時(shí)需額外邏輯來處理老的session,否則客戶端的用戶角色無法實(shí)時(shí)更新
const role = await ctx.service.user.getRoleByUsername(username);
const noPerList = options.noPermission[role];
if (noPerList && !isNoPer(noPerList,ctx.path)) {
await next();
} else {
ctx.body = '無權(quán)限,請聯(lián)系網(wǎng)站管理員!';
}
//登錄注冊頁面不需要權(quán)限
} else if (options.noAuth.includes(ctx.path)) {
await next();
//如果session失效后則重定向到登錄頁
} else {
ctx.redirect('/login.htm')
}
}
};
這時(shí)候我們的配置文件就可以支持正則表達(dá)式了:
auth : {
noAuth:['/login.htm','/user/login','/register.htm','/user/register'],
noPermission:{
admin:[],
manager:['/admin.htm'],
user:['/admin.htm','/edit.*']
}
}
結(jié)尾
如果看完覺得有用,請給作者一個(gè)喜歡吧!謝謝啦!