feathersjs 授权自定义问题

Posted

技术标签:

【中文标题】feathersjs 授权自定义问题【英文标题】:feathersjs authorization customization issue 【发布时间】:2017-10-26 17:16:27 【问题描述】:

我是使用 feathersjs 的新手,它非常灵活,对于简单的 CRUD 用例似乎非常高效。我在尝试自定义羽毛的授权时遇到了问题。此处显示了文档中用于自定义登录响应的示例。

app.service('/authentication').hooks(
  after: 
    create: [
      hook => 
        hook.result.foo = 'bar';
      
    ]
  
);

按预期工作,收到的 JSON 具有访问令牌和 foo 属性。但是,如果我修改它添加这样的钩子函数:

app.service('/authentication').hooks(
  after: 
    create: [
      hook => 
        hook.result.foo = 'bar';
      ,
      login()
    ]
  
);

或者只是

after:
  create: [ 
    login()
  ] ...

或者在之前设置,没设置新属性也没关系。登录钩子代码是:

const errors = require('feathers-errors');
const jwt = require('feathers-authentication-jwt');
const ExtractJwt = require('passport-jwt').ExtractJwt;
const moment = require('moment');

module.exports = function () 
  return function (hook) 
    // call a function that validates the username and password and returns a session id, rol and other information to fillout the payload
    const sequelizeClient = hook.app.get('sequelizeClient');
    sequelizeClient.query('SELECT ... ) // Sequelize magic
    .then(mySession =>  // session successfully created
        hook.data.resultcode = mySession[0].resultcode;
        delete hook.data.usr;
        delete hook.data.pwd;
        //payload I want, but simply doesn't go or is partially taken
        var pload =  header:  typ: 'access' ,
          strategy: 'jwt',
          'issuer': 'feathers',
          'subject': hook.data.resultcode.session_id,
          'audience': 'localhost',
          'rol': hook.data.resultcode.rol,
          'nbf': moment(),
          'iet': moment()
        ;
        var opts = 
          name: 'jwt', 
          entity: 'sessions', 
          service: 'sessions',
          passReqToCallback: false, 
          session: false // whether to use sessions,
          //Verifier: Verifier
        ;
        opts.jwtFromRequest = [ExtractJwt.fromAuthHeader(),
          ExtractJwt.fromAuthHeaderWithScheme('Bearer'),
          ExtractJwt.fromBodyField('body')
        ];
        opts.secret = 'secret';
        hook.data.payload = pload; // as documentation says to modify the payload, but does not work
        hook.params.payload = pload;
        hook.app.passport.createJWT(pload, opts)
        .then( jwtResult => 
          hook.result.token = jwtResult;
          console.log("after hook result:"+ JSON.stringify(hook.result));
          return hook;
        )
        .catch(error => 
          console.log("JWT-ERROR: "+error);
          throw new errors.GeneralError('Error generating jwt. Login failed');
        );
    ).catch(error => 
      console.log("ERROR: "+error);
      throw new errors.GeneralError('Database error');
    );
  ;
;

这段代码运行,会话在数据库中创建,一切都很好,但是在新令牌创建并显示在控制台之前,响应会发送到客户端。 foo 在那里,但不是在 hook.result 对象中添加的新令牌属性。不同的是 foo 是同步添加的,token 属性是异步设置的。我读了这个答案 (Understanding FeathersJS hooks),但是对于使用 feathers-cli 生成的代码,我不知道该怎么做,如果它适用于 Auk(我正在使用的羽毛版本)。现在我的问题:

    异步生成的令牌属性如何发送? 如何更改/覆盖令牌的有效负载、机密和选项。事实上,秘密将由会话决定,而不是像配置中那样是唯一的或系统范围的。例如,如果令牌使用 RSA 加密,系统范围内的密钥可能会被设置为公钥。 如果资源是由 REST 服务器本身计算的,那么如何创建自定义服务(不基于 sequelize、内存或其他后端)的示例在哪里?最好在文档的高级部分提供一个示例。

谢谢,如果答案很明显,很抱歉,但我还没有达到啊哈!对于第三个也是第一个问题的案例,使用 feathersjs 的时刻。

【问题讨论】:

【参考方案1】:

我终于可以做到了,我还回答了我几天前发表的另一篇文章。

我创建了另一个名为 session 的服务,并在服务创建代码中输入了这个:

module.exports = function () 
const app = this;

// Initialize our service with any options it requires
app.use('/v1/session', 
  create(data, params)
    console.log("creating service");
    const sequelizeClient = app.get('sequelizeClient');
    return sequelizeClient.query('SELECT ... //Sequelize magic must be returned its promise
    ).then(login => 
        delete data.usr;
        delete data.pwd;
        data.resultcode = login[0].resultcode;
        var payload =  'iss': 'feathers',
          'sub': data.resultcode.session_id,
          'aud': 'localhost',
          'nbf': moment(),
          'iet': moment()
        ;
        var opts = 
          name: 'jwt',
          entity: 'sessions',
          service: 'sessions',
          passReqToCallback: false,
          session: false
        ;
        opts.jwtFromRequest = [ExtractJwt.fromAuthHeader(),
          ExtractJwt.fromAuthHeaderWithScheme('Bearer'),
          ExtractJwt.fromBodyField('body')
        ];
        opts.secret = 'secret';
        return app.passport.createJWT(pload, opts) // Here is the correction return the nested promise
        .then( function(jwtResult) 
          delete data.resultcode;
          data.token = jwtResult;
          return Promise.resolve(data); // and return a promise with the desired result, which can be any object, not necessarily data or params
        )
        .catch(error => 
          console.log("JWT-ERROR: "+error);
          throw new errors.GeneralError('Error generating jwt. Login failed');
        );
      
    ).catch(error => 
      console.log("ERROR: "+error);
      throw new errors.GeneralError('Database error');
    );
  
);

由于 sequelize 查询和 createJWT 函数的异步特性,响应始终是我在创建返回中设置的任何内容。所以,我意识到要返回每个嵌套的 Promise(线索来自一个在身份验证示例中返回 createJWT 的示例),但我对 sequelize 感到困惑。最后是一个新手错误处理羽毛中的承诺。有了这个回答,我的other post也得到了回答。

谢谢。

【讨论】:

以上是关于feathersjs 授权自定义问题的主要内容,如果未能解决你的问题,请参考以下文章

C# WCF -- 通过自定义 AuthorizationManager 自定义错误授权失败

自定义授权者 + 阶段配置值

如何在 OpenAPI 3 中使用自定义前缀定义授权标头?

自定义 laravel sanctum 未授权响应

spring boot spring security 基于自定义令牌的身份验证和自定义授权

自定义授权标头