博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
nodejs的用户权限管理——acl.md
阅读量:6218 次
发布时间:2019-06-21

本文共 4723 字,大约阅读时间需要 15 分钟。

说明

Q: 这个工具用来做什么的呢

A: 用户有不同的权限,比如管理员,vip,普通用户,每个用户对应访问api,页面都不一样

nodejs有两个比较有名的权限管理模块 一个是acl 一个是rbac 综合对比了一下最终在做项目的时候选择了acl

使用方法

  1. 建立起配置文件
  2. 用户登录后分配相应的权限
  3. 需要控制的地方使用acl做校检

配置文件

const Acl = require('acl');const aclConfig = require('../conf/acl_conf');module.exports = function (app, express) {    const acl = new Acl(new Acl.memoryBackend()); // eslint-disable-line    acl.allow(aclConfig);    return acl;};// acl_confmodule.exports = [    {        roles: 'normal',  // 一般用户        allows: [            { resources: ['/admin/reserve'], permissions: ['get'] },        ]    },    {        roles: 'member',  // 会员        allows: [            { resources: ['/admin/reserve', '/admin/sign'], permissions: ['get'] },            { resources: ['/admin/reserve/add-visitor', '/admin/reserve/add-visitor-excel', '/admin/reserve/audit', '/admin/sign/ban'], permissions: ['post'] },        ]    },    {        roles: 'admin',   // 管理        allows: [            { resources: ['/admin/reserve', '/admin/sign', '/admin/set'], permissions: ['get'] },            { resources: ['/admin/set/add-user', '/admin/set/modify-user'], permissions: ['post'] },        ]    },    {        roles: 'root',  // 最高权限        allows: [            { resources: ['/admin/reserve', '/admin/sign', '/admin/set'], permissions: ['get'] },        ]    }];复制代码

校检

这里是结合express做校检...结果发现acl自己提供的中间件太鸡肋了,这里就重写了一个。

function auth() {        return async function (req, res, next) {            let resource = req.baseUrl;            if (req.route) { // 正常在control中使用有route属性 但是使用app.use则不会有                resource = resource + req.route.path;            }            console.log('resource', resource);            // 容错 如果访问的是 /admin/sign/ 后面为 /符号认定也为过            if (resource[resource.length - 1] === '/') {                resource = resource.slice(0, -1);            }            let role = await acl.hasRole(req.session.userName, 'root');            if (role) {                return next();            }            let result = await acl.isAllowed(req.session.userName, resource, req.method.toLowerCase());            // if (!result) {            //     let err = {            //         errorCode: 401,            //         message: '用户未授权访问',            //     };            //     return res.status(401).send(err.message);            // }            next();        };    }复制代码

有点要说明的是express.Router支持导出一个Router模块 再在app.use使用,但是如果你这样使用app.use('/admin/user',auth(), userRoute);那么是在auth这个函数是获取不到req.route这个属性的。 因为acl对访问权限做的是强匹配,所以需要有一定的容错

登录的权限分配

result为数据库查询出来的用户信息,或者后台api返给的用户信息,这里的switch可以使用配置文件的形式,因为我这边本次项目只有三个权限,所以就在这里简单写了一下。

let roleName = 'normal';    switch (result.result.privilege) {        case 0:            roleName = 'admin';            break;        case 1:            roleName = 'normal';            break;        case 2:            roleName = 'member';            break;    }    if (result.result.name === 'Nathan') {        roleName = 'root';    }    req.session['role'] = roleName;    // req.session['role'] = 'root';   // test    acl.addUserRoles(result.result.name, roleName);    // acl.addUserRoles(result.result.name, 'root'); // test复制代码

pug页面中的渲染逻辑控制

在 express+pug中app.locals.auth= async function(){}这个写法在pug渲染的时候是不会得出最终结果的,因为pug是同步的,那么我如何控制当前页面或者说当前页面的按钮用户是否有权限展示出来, 这里通用的做法有

  1. 用户在登录的时候有一个路由表和组件表 然后在渲染的时候 根据这个表去渲染
  2. 在需要权限控制的地方,使用函数来判断用户是否有权限访问

我这里采用的是结局方案2.因为比较方便, 但是问题来了 express+pug是不支持异步的写法,而acl提供给我们的全是异步的, 因为时间原因,我没有去深究里面的判断,而是采用了一种耦合性比较高但是比较方便的判断方法.

app.locals.hasRole = function (userRole, path, method = 'get') {    if (userRole === 'root') {        return true;    }    const current = aclConf.find((n) => {        return n['roles'] === userRole;    });    let isFind = false;    for (let i of current.allows) {        const currentPath = i.resources;  // 目前数组第一个为单纯的get路由        isFind = currentPath.includes(path);        if (isFind) {            // 如果找到包含该路径 并且method也对应得上 那么则通过            if (i.permissions.includes(method)) {                break;            }            // 如果找到该路径 但是method对应不上 则继续找.            continue;        }    }    return isFind;};复制代码

上述代码页比较简单, 去遍历acl_conf,查找用户是否有当前页面的或者按钮的权限 因为acl_conf在加载的时候就已经被写入内存了,所以性能消耗不会特别大。比如下面的例子。

if hasRole(user.role, '/admin/reserve/audit', 'post')                    .col.l3.right-align                        a.waves-effect.waves-light.btn.margin-right.blue.font12.js-reviewe-ok 同意                        a.waves-effect.waves-light.btn.pink.accent-3.font12.js-reviewe-no 拒绝复制代码

结尾

依靠acl这个组件可以快速打造一个用户的权限管理模块。 但是还有个问题 也急速那个app.locals.hasRole函数, 如果你使用removeAllow动态改变了用户的权限表,那么hasRole函数就很麻烦了。 所以在这种情况下 有以下几个解决方案

  1. 从acl源码入手
  2. 每次渲染的时候就把数据准备好
const hasBtn1Role = hasRole(user.role, '/xxx','get');res.render('a.pug',{hasBtn1Role})复制代码

转载于:https://juejin.im/post/5aa7490af265da239d48f6b4

你可能感兴趣的文章
【Web Audio API】 — 那些年的 web audio
查看>>
深入理解CAS算法原理
查看>>
构建多页的前后分离web项目(alpaca-spa的视图用法)
查看>>
Ubuntu笔记--文件关联软件
查看>>
2017 年终总结 —— 在路上
查看>>
[20180627]truncate table的另类恢复.txt
查看>>
Android DataBinding数据绑定技术在传统ListView中的使用简例
查看>>
Android - 使用Volley请求网络数据
查看>>
情出所愿 事过无悔
查看>>
java实现office文件预览
查看>>
C# TextBox 焦点
查看>>
TCP协议解析
查看>>
Spark on Yarn 架构解析
查看>>
SqlServer建立存储过程,方便.NET插入自增字段
查看>>
Servlet第五篇【介绍会话技术、Cookie的API、详解、应用】
查看>>
千奇百怪的陆地机器人,都是怎么“跑”起来的?
查看>>
ODCC开放数据中心峰会即将召开 十道“技术大餐”提前揭秘
查看>>
深度学习机器学习:softmax和log_softmax区分
查看>>
公司环境搭建(windows10)
查看>>
给1~3年iOS经验朋友们的一些建议(附BAT面经)
查看>>