有两个关于refreshToken的问题
来源:7-1 Redux 的概念和实战(一)

123321_0015
2019-05-02
老师,您好!
第一个问题:我想问一些关于redux相关的问题。我发现当redux涉及到refreshToken时,会有些异步的问题,因为所有的返回值都是observable,且dispatch操作是没有顺序的,这样会导致不能先refreshToken后再去发送http请求。这里如果用effect应该怎么设计呢?谢谢老师!
第二个问题:我需要refreshToken时是在angular的拦截器里调的服务,这样就会有一个小问题,当在很短时间内有大量请求时,就会发生refreshToken的http请求服务还没有得到返回值时就再一次调用这个refreshToken请求服务,会造成refreshToken没有更新,以后会全部http请求失败,请问有什么好的解决方案吗?需要我每次请求时设置一个延时吗?谢谢老师!
这是在angular的拦截器中我写的代码
intercept(
req: HttpRequest,
next: HttpHandler
): Observable<HttpEvent> {
if (req.url.includes('authentication')) {
return next.handle(req);
}
return this.authService.refresh(getJwtToken(), getRefreshToken()).pipe(
take(1),
switchMap(auth => {
saveJwtToken(auth.token);
saveRefreshToken(auth.refreshToken);
// req.headers.set('Authorization', `${auth.token_type} ${auth.token}`);
let newHeaders = req.headers;
newHeaders = newHeaders.delete('Authorization');
newHeaders = newHeaders.append(
'Authorization',
`${auth.token_type} ${auth.token}`
);
const dummyrequest = req.clone({
headers: newHeaders
});
return next.handle(dummyrequest);
}),
catchError(err => {
this.router.navigate(['/login']);
return of(err);
})
);
}
写回答
2回答
-
import { Injectable } from "@angular/core"; import { HttpInterceptor, HttpEvent, HttpRequest, HttpHandler } from "@angular/common/http"; import { BehaviorSubject, Observable } from "rxjs"; import { catchError, switchMap, filter, take } from "rxjs/operators"; @Injectable({ providedIn: 'root' }) export class RefreshTokenInterceptor implements HttpInterceptor { private refreshTokenInProgress: boolean = false; private refreshTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>( null ); constructor(public accountService: AccountService) {} intercept(request: HttpRequest<any>,next: HttpHandler): Observable<HttpEvent<any>> { // 首先检查 token 是否过期 // 如果没有过期,在 Request Headere 添加鉴权头 addAuthenticationToken(); // 如果过期 if (tokenHasExpired()) { if (this.refreshTokenInProgress) { // 如果 refreshTokenInProgress 为真, 我们需要等到 refreshTokenSubject 有非 null 值 // 此时才意味着新的 token 已经准备好了,我们可以重试请求 return this.refreshTokenSubject.pipe( filter(result => result !== null), take(1), switchMap(() => next.handle(this.addAuthenticationToken(request))) ); } else { this.refreshTokenInProgress = true; // 设置 refreshTokenSubject 为 null,这样后继的请求会等待新 token 的生成 this.refreshTokenSubject.next(null); return this.accountService.renewToken() .pipe( switchMap(t => { this.accountService.saveToken(t); let token = this.accountService.getAccessToken(); this.refreshTokenInProgress = false; // 设置 refreshTokenInProgress 为 False this.refreshTokenSubject.next(token); // 发射新 token var newReq = this.setToken(req, token); return next.handle(newReq); }), catchError((err) => { this.refreshTokenInProgress = false; return Observable.throw(err); }) ); } } else { return this.addAuthenticationToken(request); } } addAuthenticationToken(request) { // 从本地取 token const accessToken = this.accountService.getAccessToken(); // 如果 access token 是 null,说明用户没有登录 // 直接返回原来的请求 if (!accessToken) { return request; } // clone 请求, 添加 header return request.clone({ setHeaders: { Authorization: accessToken } }); } }
012019-05-03 -
接灰的电子产品
2019-05-02
refresh token 的操作可以放在interceptor 中,这样就不用每个请求都处理了。
此外如果先需要执行某个操作。然后再执行某个操作、这个和redux 无关。使用 rx 很方便的可以处理
first$.switchMap(f => second$)012019-05-02
Angular打造企业级协作平台,让你在Angular领域中出类拔萃
全网首个介绍官方 Material 组件库用法与 Redux 在 Angular 中的应用
998 学习 · 536 问题
相似问题