我的应用程序使用带有令牌的SSO身份验证,该令牌可能会过期。
点击" admin"按钮,我需要为页面的几个部分调用几个WS(这些调用没有链接)。
如果我的令牌过期,则第一次WS调用将导致401错误。然后我会要求更新令牌。 我试图做的是保持跟随ws呼叫,直到令牌更新完成。
我有类似的东西:
private isTokenBeingRenewed: BehaviorSubject<boolean> = new BehaviorSubject(false);
...
private handleAccessTokenExpiration(wsCall: Function, growlSuccessMsg: string, growlTitle?: string): Observable<Response> {
// flag token being renewed
this.isTokenBeingRenewed.next(true);
//start token renewal
return this.oidcSecurityService.refreshSession().flatMap(event => {
// Call WS again when token is renewed
return wsCall()
.catch(error => {
return Observable.throw(...);
})
.do((res: Response) => {
...
}, (error: any) => {
return Observable.throw(...);
})
.finally(() => {
// flag token renewal is done
this.isTokenBeingRenewed.next(false);
});
});
}
在我的ws呼叫功能上我有:
private handleWSResponse(wsCall: Function,
showGrowlSuccess: boolean,
growlTitle?: string,
growlSuccessMsg?: string): Observable<Response> {
// Avoid call renew multiple times.
return this.isTokenBeingRenewed.flatMap(isRenewing => {
// If token renewal is not in progress, calls WS
if (!isRenewing) {
// Call WS
}
}
}
问题是,当isRenewing === true时,Observable已解决,但不会返回任何内容。如果isRenewing = true,我不知道如何等待和解决?
答案 0 :(得分:0)
所以,您要做的是,如果续订token
,请立即致电wsCall
,如果token
未续订,请致电handleAccessTokenExpiration
,然后致电{{ 1}}。您可以使用wsCall
来执行&#34;等待&#34;:
switchMap()
或者您可以在一个班轮中完成:
private handleWSResponse(wsCall: Function,
showGrowlSuccess: boolean,
growlTitle?: string,
growlSuccessMsg?: string): Observable<Response> {
if (this.isTokenBeingRenewed) {
return wsCall();
} else {
//handle token first
//arguments here is omitted for brevity
return this.handleAccessTokenExpiration()
.switchMap(() => wsCall());
}
}
答案 1 :(得分:0)
你应该使用HttpInterceptor来实现它!
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
private authService: AuthService;
constructor(private inj: Injector) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (request.url.includes('/not-authorized')) {
return next.handle(request);
}
this.authService = this.inj.get(AuthService);
return this.authService.getRawAccessToken()
.switchMap(token => {
request = request.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
return next.handle(request);
});
}
}
该示例与您的方案不完全匹配,但方法应该这样做。 这样的事情。在这里,您必须划分必须获得授权的API。然后,您可以在auth服务中检查令牌过期。只有令牌再次有效时,“authservice”提供的Observable才应解决。然后你有一个点可以控制每个呼叫。 在我看来,这是最简单的方法。 此外,在这种场景中,应该使用switchMap。
如果您在这里不使用Angular,也可以使用相同的概念。只需订阅行为主题并过滤所有错误值。但是,如果您始终对第一个服务进行异步调用以检查令牌是否已过期,则您将始终丢失一些调用。您应该可以使用oidc synchronous来检查到期时间:
private isTokenBeingRenewed: BehaviorSubject<boolean> = new BehaviorSubject(false);
public handleAccessTokenExpiration(): Observable<boolean> {
this.isTokenBeingRenewed.next(true);
//start token renewal
this.oidcSecurityService.refreshSession()
.subscribe(event => this.isTokenBeingRenewed.nect(false);
return this.isTokenBeingRenewed;
}
在来电者中:
public doSth() {
handleAccessTokenExpiration
.filter(result => !result)
.switchMap(result => doWsCall())
.sunscribe();
}
如果你的电话没有被观察到。只是包裹它。