首页 文章

如何在ember-simple-auth会话中从响应头更新JWT令牌

提问于
浏览
-2

我正在使用ember-simple-auth和ember-simple-auth-token来维护Ember上的会话 . 我不想使用刷新令牌方法,而是希望在每个服务请求的响应头中接收新的jwt令牌 .

每次从服务器收到响应时,如何通过更新会话中的jwt令牌来保持会话的活动状态?

1 回答

  • 1

    这可以完成,但需要扩展 ember-simple-authember-simple-auth-token . 它需要能够进行身份验证,只需要授权和验证令牌 . 它还为每个请求生成一个新令牌增加了一些开销 . 虽然我不知道如何做到这一点:

    正如您所发现的那样,您无法直接更新会话,但如果您深入了解源代码,您会发现 ember-simple-auth 使用event来更新它 . 但是,此事件仅在您覆盖/自定义 authenticator 时才有效 . 可能 ember-simple-auth-tokenauthenticators/jwt.js . 如果您查看其身份验证器,您可以看到如何update the session的示例 .

    因此,我建议您创建自己的自定义JWT令牌身份验证器,扩展 ember-simple-auth-token . 它可能会添加一个更新 session 的方法,或者更好地处理包含新访问令牌的原始请求标头 .

    完成后,您可以选择 . 您可以覆盖自己的 adapter 并从那里自己调用该函数,或者更好的选择是覆盖 ember-simple-authdata-adapter-mixin mixin .

    如果你重写 ember-simple-auth data-adapter-mixin ,这似乎是最好的起点:handleResponse . 如果覆盖该功能,则应该可以访问原始API响应,您可以从中调用更新会话功能 .

    正如您所看到的,这不是一个微不足道的变化 . 它绝对违背了这些库最初设计的内容,但是如果你付出了很多工作,它应该是可能的 .

    Updates for OP's comment
    我之前实际上实现了这两个要求:"1) to have session timeout after a pre configured idle time. 2) allow certain set of users to proxy in and switch the context of login user on the fly" . 事实证明,使用刷新令牌模型实际上很容易实现 .

    要支持#1,刷新令牌到期应设置为注销前的空闲时间长度 . 例如如果刷新令牌设置为在30分钟后过期,则访问令牌在5分钟后到期 . 客户端将根据余地每隔约5分钟自动获取新的访问令牌(以及可选的刷新令牌) . 但是,如果用户离开页面超过30分钟,则刷新令牌将过期,并且需要重新进行身份验证 .

    对于#2,不幸的是,它确实需要一些覆盖 ember-simple-auth-token 才能工作,但它相对容易,我已经实现了 . 基本上,您创建一个自定义身份验证器,该身份验证器具有一个附加功能,用于交换和访问具有更新上下文/状态的新令牌 . 请参阅下面的实施:

    ember-simple-auth-token 重写身份验证器:

    /**
        Provides a public method to call to exchange an access token for an
        updated access token with updated data encoded in it. This method
        essentially asks the backend to update an access token with different
        values. This is, at the moment, is only used to switch the company root
        attribute in the token (AKA switch companies for admins).
    
        @param {string} token - The valid access token
        @param {object} [headers] - An optional object which can add additional
        headers to the request
    
        @param {object} additionalData - An object which contains the data which should be updated on the token. It should look  something like this:
        ```
        {
            company_root_id: '<UUID of a valid company root>'
        }
        ```
        @return {Promise} A promise which is the request. It will either resolve
        with the updated session data or reject with the error.
      */
     exchangeAccessToken(token, headers, additionalData) {
         const data = this.makeRefreshData(token);
         Ember.merge(data, additionalData);
    
         return new Ember.RSVP.Promise((resolve, reject) => {
             this.makeRequest(this.serverTokenRefreshEndpoint, data, headers).then(response => {
                 Ember.run(() => {
                     try {
                         const sessionData = this.handleAuthResponse(response);
    
                         this.trigger('sessionDataUpdated', sessionData);
                         resolve(sessionData);
                     } catch(error) {
                         reject(error);
                     }
                 });
             }, (xhr, status, error) => {
                 Ember.Logger.warn(`Access token could not be refreshed - server responded with ${error}.`);
                 reject();
             });
         });
     }
    

    触发令牌交换的操作:

    switchCompany(companyId) {
         let session = this.get('_session.session');
    
         if(!this.get('isAdministrator')) {
             throw new Error('Logged in user is not an administrator, they cannot switch companies.');
         }
    
         let token = session.get('authenticated.access_token');
         let appInstance = Ember.getOwner(this);
         let authorizerName = session.get('authenticator');
         let authorizer = appInstance.lookup(authorizerName);
         if(!authorizer) {
             throw new Error(`Authorizer (${authorizerName}) does not exist`);
         }
         if(typeof authorizer.exchangeAccessToken !== 'function') {
             throw new Error(`Authorizer (${authorizerName}) does not have an \`exchangeAccessToken\` method.`);
         }
         return authorizer.exchangeAccessToken(token, null, {
             company_root_id: companyId
         });
     }
    

    显然需要扩展后端以接受刷新令牌 endpoints 上的其他参数,这允许用户切换角色(如果已授权) .

相关问题