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



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

如何通过在每次收到来自服务器的响应时更新会话中的 JWT 令牌来保持会话处于活动状态?

这是可以做到的,但需要扩展ember-simple-authember-simple-auth-token。不完全建议使用您的方法,访问令牌加刷新令牌绝对是首选方法。它还可以更好地扩展,因为资源服务器不需要身份验证功能,只需授权和验证令牌即可。它还增加了一些开销,为每个请求生成一个新令牌。虽然我不推荐这门课程,但这是如何完成的:

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

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

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

如果覆盖ember-simple-authdata-adapter-mixin,这似乎是最好的起点:handleResponse。如果重写该函数,则应有权访问原始 API 响应,从中可以调用更新会话函数。

如您所见,这不是一个微不足道的变化。这绝对违背了这些库最初设计的目的,但如果你投入大量工作,这应该是可能的。

OP评论的更新
我实际上之前实现了这两个要求:"1)在预先配置的空闲时间后会话超时。2)允许某些用户代理并动态切换登录用户的上下文"。事实证明,使用刷新令牌模型实际上很容易完成。

若要支持 #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
});
}

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

最新更新