我正在使用AWS Cognito对Angular应用程序中的用户进行身份验证。我想在每个小时到期之前自动刷新会话。
我们使用Angular拦截器类在每个请求的标头中设置访问令牌。用户登录后,时间将保存并存储在本地存储中。在每个HTTP请求之前都会对此进行检查,如果周期大于一小时,请从amazon-cognito-identity-js库调用cognito用户池refreshSession函数。
但是,这种方法似乎无法无缝刷新会话。我已经能够刷新会话,但是进行的调用返回401,只有在此之后,会话才会被刷新。
拦截器如下:
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const invalid = this.checkSessionNotValidViaStorage();
if (invalid) {
return from(this.authenticationService.refreshSessioFromPromise()).pipe(result => {
const newRequest = this.setHeader(request);
return next.handle(newRequest);
});
} else {
const newRequest = this.setHeader(request);
return next.handle(newRequest);
}
}
身份验证服务如下:
refreshSessioFromPromise(): Observable<string> {
return from((resolve: any, reject: any) => {
const currentUser = this.getCurrentUser();
currentUser.getSession((getSessionErr: any, getSessionSession: any) => {
const refreshToken = getSessionSession.getRefreshToken();
currentUser.refreshSession(refreshToken, (refreshSessionErr, refreshSessionSession) => {
if (refreshSessionErr) {
reject('Cognito: Can not set the credentials:' + refreshSessionErr);
} else {
this.setCredentials(refreshSessionSession, this.remember);
this._credentials = refreshSessionSession;
resolve('Cognito: refreshed successfully');
}
});
});
});
}
这种使用RxJs from函数的方法基于the article by Michael Karén Michael Karén。
我也尝试过使用promise和其他RxJs方法。好像amazon-cognito-identity-js lib正在丢弃异步球,因此,最大的问题是如何确保在允许任何更多调用继续之前刷新会话。
可能使用拦截器不是正确的方法,并且在HTTP服务之上需要有另一层来实现此目的。
对于使用适当的RxJs / Angular拦截器方法进行此操作的任何帮助,或者其他更好的方法,将不胜感激。
答案 0 :(得分:0)
错误在于拦截功能。像这样重构它:
from(this.authenticationService.refreshSessioFromPromise()).pipe(
switchMap(result => {
const newRequest = this.setHeader(request);
return next.handle(newRequest);
})
)
管道函数需要RxJS运算符。在这种情况下,我们应该获取auth服务的observable返回的值,并切换到next.handle调用返回的observable。
因为我们要从一个可观察的对象转到另一个可观察的对象,所以我们需要使用扁平化运算符。转换为可观察值的承诺会发出一个值,然后完成。这意味着我们不必担心扁平化策略,使用简单的switchMap
就可以了。如果您对其他扁平化策略感到好奇,请查看concatMap
,exhaustMap
和mergeMap
运算符,