node权限控制模块node_acl的应用

前言

  • 一个应用必不可少的部分:登录认证(jaredhanson/passport)、权限控制(OptimalBits/node_acl)
  • 由于node_acl中文资料较少,本文给出一个完整的简单示例,便于初学者理解和学习
  • 最后有动态的效果图给出,更直观的展示node_acl的使用效果

知识点

  • 示例中的路由并未采用如:app.put('/blogs/:id', function(req, res, next){//…}的restful风格架构
  • 使用mongoose连接数据库
  • 初始化所有角色的权限
  • 建立父级角色(父级角色拥有子级角色所有权限)
  • 为用户添加角色(添加后,用户拥有该角色的所有权限)
  • es6模板字符串
  • 创建数据库schema模型
  • 为schema添加静态方法
  • 使用session保持会话
  • 自定义node_acl的认证失败后的错误信息
  • 使用错误中间件

示例

Promise = require('bluebird')
var express = require('express')
var mongoose = require('mongoose')
var session = require('express-session')
var MongoStore = require('connect-mongo')(session)
var acl = require('acl')

var app = express()

/*
 * ------------------------------------------------
 * 数据库
 */
mongoose.Promise = Promise
mongoose.connect('127.0.0.1:30001/blog')// 连接你自己的数据库
.then(() => {// 这里要注意,一定要在连接数据库之后进行权限的操作,否则不生效
    roles()// 权限
    routes()// 路由
})

app.use(session({
    secret: 'sign',
    resave: true,
    saveUninitialized: true,
    store: new MongoStore({mongooseConnection: mongoose.connection}),
}))

/*
 * --------------------------------------------------
 * 权限
 */
function roles() {
    acl = new acl(new acl.mongodbBackend(mongoose.connection.db, 'acl_'))
    // 为guestuseradmin角色添加权限
    acl.allow([
        {
            roles: 'guest',
            allows: [
                {resources: '/article/get', permissions: '*'},
            ],
        },
        {
            roles: 'user',
            allows: [
                {resources: '/article/edit', permissions: '*'},
            ],
        },
        {
            roles: 'admin',
            allows: [
                {resources: '/article/del', permissions: '*'},
            ],
        }
    ])
    acl.addRoleParents('user', 'guest')// user角色拥有guest角色所有的权限
    acl.addRoleParents('admin', 'user')// admin角色拥有user角色所有的权限
}

/*
 * --------------------------------------------------
 * 路由
 */
function routes() {
    // 渲染主页面
    app.all('/', (req, res, next) => {
        var html = `
            <div>
                <input class="name" type="text" placeholder="输入用户名" value="${Date.now()}" autocomplete="off">
                <button class="add">创建用户</button>
                <p>guest角色可以访问/article/get,user角色可以访问/article/edit,admin角色可以访问/article/del</p>
                <p>默认情况下,访问1、2、3都会被拒绝</p>
                <p>创建用户后,会自动给新创建的用户添加guest和 user角色,所以允许访问1、2</p>
                <p>点击4后,删除了用户的user角色,只能访问1了</p>
                <p>
                    <span>1.</span>
                    <a href="/article/get" target="_blank">访问/article/get</a>
                </p>
                <p>
                    <span>2.</span>
                    <a href="/article/edit" target="_blank">访问/article/edit</a>
                </p>
                <p>
                    <span>3.</span>
                    <a href="/article/del" target="_blank">访问/article/del</a>
                </p>
                <p>
                    <span>4.</span>
                    <a href="/user/del" target="_blank">删除用户的user角色</a>
                </p>
            </div>
            <script> window.onload = function() { document.querySelector('.add').onclick = function() { window.open('/user/add?name='+ document.querySelector('.name').value) } } </script>
        `
        res.send(html)
    })


    var User = schema()// 获取用户模型实例
    // 添加角色
    app.all('/user/add', (req, res, next) => {
        User.add(req.query)
        .then((user) => {
            var _id = user._id.toString()// 注意_id默认是object类型
            req.session.userId = _id// 写入session,标识该用户
            acl.addUserRoles(_id, ['guest', 'user'])// 为用户添加guest和user的角色(那么用户就拥有了guest和user的权限)
            res.send({message: '添加用户角色成功'})
        })
        .catch((e) => {
            res.send({message: e.message})
        })
    })
    // 删除角色
    app.all('/user/del', (req, res, next) => {
        acl.removeUserRoles(req.session.userId, 'user')
        res.send({message: '删除用户角色成功'})
    })
    // 访问article
    app.all('/article/get', authentication, (req, res, next) => {
        res.send({message: '/article/get'})
    })
    // 编辑article
    app.all('/article/edit', authentication, (req, res, next) => {
        res.send({message: '/article/edit'})
    })
    // 删除article
    app.all('/article/del', authentication, (req, res, next) => {
        res.send({message: '/article/del'})
    })
    app.use(errorhandler)
}

/*
 * --------------------------------------------------
 * schema
 */
function schema() {
    var schema = new mongoose.Schema({
        name: {
            type: String,
        },
    })

    schema.statics = {
        add: function(obj) {
            return this
            .create(obj)
        },
    }

    return mongoose.model('User', schema);
}

/*
 * --------------------------------------------------
 * 中间件
 */
// 认证中间件
var authentication = (req, res, next) => {
    var userId =req.session.userId || ''

    if(userId) {
        acl.isAllowed(userId, req.path, '*')
        .then(allowed => {
            if(allowed) {
                next()
            }else {
                next('权限不足')
            }
        })
        .catch((e) => {
            next(e.message)
        })
    }else {
        next('请登录')
    }

}
// 错误中间件
var errorhandler = (e, req, res, next) => {
    res.send({message: e})
}

/*
 * --------------------------------------------------
 * 开启服务
 */
app.listen(3001, () => {
    console.log('server...')
})

解释


  • 打开http://127.0.0.1:3000/可以看到
    这里写图片描述
  • 数据库结构
    这里写图片描述
  • 创建用户前访问接口(此时是未登录状态,没有任何权限)
    这里写图片描述
  • 创建用户后访问接口(新用户自动添加guest和user角色,可访问1、2)
    这里写图片描述
  • 删除user角色后(只能访问1)
    这里写图片描述

icompuiz/express-mongoose-acl
Running ‘node_acl’ with mongoose on ExpressJS
RBAC角色权限设计思路

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值