[英]Angular - Waiting for refresh token function to finish before forwarding the request
我正在 angular 中的身份验证系统上工作,后端为 django,后端为 jwt。我有一个 angular 拦截器,它在每个请求中检查访问令牌是否仍然有效,如果无效,它会调用 refreshtoken function 并刷新访问令牌。
下面是拦截器的代码:
constructor(private authService:AuthService) {}
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
let access_token = localStorage.getItem("access_token");
if(access_token){
// Check if access token is no longer valid, if so, refresh it with the refresh token
if(this.authService.isLoggedOut()){
this.authService.refreshToken();
access_token = localStorage.getItem("access_token");
}
const cloned = request.clone({
headers: request.headers.set("Authorization", "Bearer " + access_token)
});
return next.handle(cloned);
}
else{
return next.handle(request);
}
它获取 access_token 并在 auth 服务的帮助下检查有效性。 我的问题是,如果它无效,它调用 refreshToken() function 看起来像这样,
refreshToken(){
let refresh_token = localStorage.getItem("refresh_token");
console.log("BEFORE REFRESH: " + localStorage.getItem("access_token"));
return this.http.post(`${apiUrl}token/refresh/`, {"refresh" : refresh_token}).subscribe(res => {
let access_token = res["access"]
const expiresAt = this.tokenExpiresAt(access_token);
localStorage.setItem("access_token", access_token);
localStorage.setItem("expires_at", JSON.stringify(expiresAt.valueOf()));
console.log("AFTER REFRESH: " + localStorage.getItem("access_token"));
});
}
但它不会等待刷新令牌 function 完成并返回句柄。 因此,带有无效令牌的第一个请求会抛出错误,只有下一个请求才正常。
我如何修改它以等待 refreshToken() 完成?
谢谢你的时间!
您可以使用rxjs
运算符,例如switchMap
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
let access_token = localStorage.getItem("access_token");
if (access_token) {
// Check if access token is no longer valid, if so, refresh it with the refresh token
if (this.authService.isLoggedOut()) {
return this.authService.refreshToken().pipe(
switchMap(token => {
const cloned = request.clone({
headers: request.headers.set("Authorization", "Bearer " + access_token)
});
return next.handle(cloned);
})
)
}
} else {
return next.handle(request);
}
}
在refreshToken
function - 让它返回Observsble
并在pipe
中设置localStorage
refreshToken(){
let refresh_token = localStorage.getItem("refresh_token");
console.log("BEFORE REFRESH: " + localStorage.getItem("access_token"));
return this.http.post(`${apiUrl}token/refresh/`, {"refresh" : refresh_token}).pipe(tap(res => {
let access_token = res["access"]
const expiresAt = this.tokenExpiresAt(access_token);
localStorage.setItem("access_token", access_token);
localStorage.setItem("expires_at", JSON.stringify(expiresAt.valueOf()));
console.log("AFTER REFRESH: " + localStorage.getItem("access_token"));
});
)
}
我结合了多个问题的答案,最后想出了这个解决方案:
拦截器:
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
let access_token = localStorage.getItem("access_token");
if (access_token) {
// Check if access token is no longer valid, if so, refresh it with the refresh token
if (this.authService.isLoggedOut()) {
return from(this.authService.refreshToken()).pipe(
mergeMap((access_token) => {
localStorage.setItem("access_token", access_token);
const cloned = request.clone({
headers: request.headers.set("Authorization", "Bearer " + access_token),
});
return next.handle(cloned);
})
);
}
const cloned = request.clone({
headers: request.headers.set("Authorization", "Bearer " + access_token),
});
return next.handle(cloned);
} else {
return next.handle(request);
}
}
刷新令牌:
async refreshToken(): Promise<string> {
let refresh_token = localStorage.getItem("refresh_token");
const res$ = this.http
.post(`${apiUrl}token/refresh/`, { refresh: refresh_token })
.pipe(map((res) => res["access"]))
.pipe(first());
const res = await lastValueFrom(res$);
const expiresAt = this.tokenExpiresAt(res);
localStorage.setItem("access_token", res);
localStorage.setItem("expires_at", JSON.stringify(expiresAt.valueOf()));
console.log("Refreshed Access Token");
return res;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.