【问题标题】:How to access node acl across multiple modules?如何跨多个模块访问节点acl?
【发布时间】:2016-02-11 14:00:56
【问题描述】:

我在理解如何将Node ACL 与猫鼬模块一起使用时遇到了一些麻烦。只要所有内容都在一个文件中,我就可以让它运行良好。但是,如果我想将路由分解为单独的文件,如何访问其他模块中的 acl 实例?

我可以让 acl 正常使用以下代码。它初始化,在数据库中创建集合,并向用户添加权限。

// App.js
const mongoose = require('mongoose');
const node_acl = require('acl');
const User = require('./models/User');

mongoose.connect(/* connection string */);

acl = new node_acl(new node_acl.mongodbBackend(mongoose.connection.db, '_acl'));
acl.allow([
  {
    roles: ['guest'],
    allows: [{ resources: 'login', permissions: 'get' }],
  },
  {
    roles: ['admin'],
    allows: [{ resources: '/users', permissions: '*' }]
  }
]);

var user = User.findOne({username: 'coffee'}, (err, user) => {
  console.error(user.id);
  acl.addUserRoles(user.id, 'admin');
});

我想不通的是如何像这样在另一个模块中正确访问 acl 实例。

// routes/foo.js
const acl = require('acl');
const router = require('express').Router();

// initialize acl ?

router.route('/', acl.middleware(/* rules */), (req, res) => {
  // route logic
});

module.exports = router;

此代码产生以下错误:TypeError: acl.middleware is not a function

我是否需要在每个路由模块中使用数据库连接创建一个新的 acl 实例?如果是这样,再次从 Mongoose 获得连接的最佳方式是什么?如果没有,或者有没有办法将它传递给每条路线?

谢谢!

【问题讨论】:

    标签: javascript node.js acl


    【解决方案1】:

    您可以通过请求变量共享对象:

    app.js:

    acl = new node_acl( new node_acl.mongodbBackend(mongoose.connection.db, '_acl'));
    // add this before routers:
    app.use( function( req, res, next) {
      req.acl = acl;
      next();
    }); 
    

    routes/foo.js:

    router.route('/', (req, res) => {
      console.log(req.acl);
      // route logic
    });  
    

    【讨论】:

    • 在该示例中,acl.middleware() 仍然是未定义的,直到您在处理程序中获取请求对象,所以中间件仍然无法正常工作,对吧?
    【解决方案2】:

    正如 IOInterrupt 建议的那样,您应该创建一个辅助模块,这就是我的工作方式:

    security.js

    'use strict';
    
    var node_acl = require('acl'),
        log = require('../log')(module),
        redis = require('../db/redis'),
        acl;
    
    var redisBackend = new node_acl.redisBackend(redis, 'acl');
    acl = new node_acl(redisBackend, log);
    set_roles();
    
    function set_roles () {
    
        acl.allow([{
            roles: 'admin',
            allows: [{
                    resources: '/api/conf',
                    permissions: '*'
                }
            ]
        }, {
            roles: 'user',
            allows: [{
                resources: 'photos',
                permissions: ['view', 'edit', 'delete']
            }]
        }, {
            roles: 'guest',
            allows: []
        }]);
    
        acl.addUserRoles('5863effc17a181523b12d48e', 'admin').then(function (res){
            console.log('Added myself ' + res);
        }).catch(function (err){
            console.log('Didnt worked m8' + err);
        });
    
    }
    
    module.exports = acl;
    

    我第一次在我的 app.js 上调用它

    app.js

    // .. a bunch of other stuff 
    var app = express();
    
    require('./config/express')(app);
    require('./config/routes')(app, jwtauth.jwtCheck);
    require('./config/security'); // just like this
    
    connect().on('error', console.log)
             .on('disconnected', connect)
             .once('open', function (){
                log.info('Connected to DB!!!');
             });
    // .. a bunch of other stuff 
    

    然后在我的路由文件 conf.js 上像这样:

    conf.js

        log = require(libs + 'log')(module),
        acl = require('../config/security'),
        isauth = require(libs + 'auth/isAuthorized'),
        redis = require('../db/redis');
    
    //               This is where the magic ensues
    router.get('/', acl.middleware(2,isauth.validateToken,'view'), function (req, res) {
        Conf.findById(req.query.id).then(function (conf) {
            return res.json(conf);
        }).catch(function (err) {
    

    不用担心在每次导入时调用 mongo 连接,因为在这里您将使用 require('../config/security') 所以它们都将获得相同的对象,因为导出在期间被缓存第一次在 app.js 调用它。我的意思是,这将不会每次都创建一个 mongodb 连接。

    【讨论】:

    • 我收到 Unhandled rejection TypeError: Cannot read property 'collection' of undefined 错误。我认为这是因为我使用的是 OP 使用的猫鼬,但您使用的是 redis。我可以用mongoose.connection.on 包装它,但我不确定如何提取acl 实例。
    【解决方案3】:

    我建议创建一个帮助模块来初始化 acl。然后,您可以在可能需要它的任何其他模块中使用它,例如您的路线。

    【讨论】:

    • 如果我写一个可以初始化acl的辅助模块,那不会创建几十个到数据库的连接吗?还是只连接一次?
    【解决方案4】:

    您可以使用app.locals 在应用程序中存储全局对象。

    在你的app.js:

    app.locals.acl = acl;
    

    然后在任何请求中,您都可以通过req.app.locals.acl 取回:

    route.get('/some-resource', function (req, res, next) {
    
        let acl = req.app.locals.acl
        ...
    }
    

    https://expressjs.com/en/api.html#app.locals签出app.locals文档

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-01-15
      • 2018-07-22
      • 1970-01-01
      • 2015-04-14
      • 2019-10-17
      • 2021-04-27
      • 2021-04-01
      • 2020-10-16
      相关资源
      最近更新 更多