【问题标题】:Store Ability in Express Session?快速会话中的存储能力?
【发布时间】:2021-06-01 03:22:57
【问题描述】:

我已经看到了一个快速的例子,其中一个能力通过中间件存储在 req 对象中。然后它使用以下方法评估权限:

ForbiddenError.from(req.ability).throwUnlessCan('read', article);

我想实现类似的事情。我的想法是将能力保存在与 socket io websockets 共享的快速会话中。通过分享req.session=socket.handshake.session。我的方法如下,我从前端应用程序发出请求以获取规则以更新前端的能力。后端将能力保存在 express 会话中:

// abilities.js file
import { Ability } from '@casl/ability';

export const defineAbilitiesFor = (rules) => {
  return new Ability(rules);
};

export default defineAbilitiesFor;
// handler for express route to get permissions from the frontend
export const getPermissions = async (req, res) => {
...
  rules.push({
    action: ['view'],
    subject: views,
  });
  // manage all own processes
  rules.push({
    action: ['manage'],
    subject: 'Process',
    conditions: {
      userId: req.kauth.grant.access_token.content.sub,
    },
  });
// store ability in session
  req.session.rules = defineAbilitiesFor(rules);
  const token = jwt.sign({ token: packRules(rules) }, 'secret');
  if (token) {
    return res.status(200).json(token);
  } else {
    return res.status(400).json('Error');
  }
...

然后,当发生 websocket 请求时,我想在后端检查用户是否有权执行该操作:

ForbiddenError.from(socket.handshake.session.rules).throwUnlessCan('view', 'Process');

但是,这会引发以下错误:

TypeError: this.ability.relevantRuleFor is not a function
    at ForbiddenError.throwUnlessCan

会话对象似乎具有正确的能力对象。当我 console.log socket.handshake.session.rules 时,我得到以下输出:

{
  h: false,
  l: {},
  p: {},
  '$': [
    { action: [Array], subject: 'Process', conditions: [Object] },
    { action: [Array], subject: [Array] },
    { action: [Array], subject: 'Process', conditions: [Object] }
  ],
  m: {}
}

can 的功能和我尝试的其他所有方法都不起作用。我认为将普通规则存储为会话中的对象,然后在每个请求起作用之前更新能力类,但我不想这样做。我想将能力存储在会话中,这样我只需要执行 throwUnlessCan 或 can 函数。

这有可能吗?如果有,你会怎么做?

到目前为止,谢谢。

【问题讨论】:

    标签: express session express-session casl


    【解决方案1】:

    您不需要存储整个Ability 实例,而只需要存储它的规则! rules是一个简单的js对象数组,所以可以很方便的序列化。所以,把代码改成这样:

    export const getPermissions = async (req, res) => {
    ...
      rules.push({
        action: ['view'],
        subject: views,
      });
      // manage all own processes
      rules.push({
        action: ['manage'],
        subject: 'Process',
        conditions: {
          userId: req.kauth.grant.access_token.content.sub,
        },
      });
    // store ability RULES in session
      req.session.rules = rules;
      const token = jwt.sign({ 
        token: packRules(rules)  // packRules accepts an array of RawRule! not an Ability instance
      }, 'secret');
    
      if (token) {
        return res.status(200).json(token);
      } else {
        return res.status(400).json('Error');
      }
    

    要在其他处理程序中使用Ability,请添加一个中间件:

    function defineAbility(req, res, next) {
      if (req.session.rules) {
        req.ability = new Ability(req.session.rules);
        next();
      } else {
        // handle case when there is no rules in session yet
      }
    }
    
    // later
    
    app.get('/api/users', defineAbility, (req, res) => {
      req.ability.can(...);
      // or
      ForbiddenError.from(req.ability).throwUnlessCan(...);
    })
    

    【讨论】:

      猜你喜欢
      • 2016-07-06
      • 2012-05-03
      • 1970-01-01
      • 2015-07-05
      • 2022-01-26
      • 2016-10-21
      • 1970-01-01
      • 1970-01-01
      • 2021-08-05
      相关资源
      最近更新 更多