Angular 在发出克隆请求之前续订令牌
因此,如果令牌使用刷新令牌过期,我想续订访问令牌,这就是我的令牌拦截器的外观:Angular 在发出克隆请求之前续订令牌,angular,typescript,jwt,jwt-auth,refresh-token,Angular,Typescript,Jwt,Jwt Auth,Refresh Token,因此,如果令牌使用刷新令牌过期,我想续订访问令牌,这就是我的令牌拦截器的外观: intercept(req: HttpRequest<any>, next: HttpHandler) { let authservice = this.injector.get(AuthService) let tokenreq = req.clone({ setHeaders: { Authorization: `Bearer ${authser
intercept(req: HttpRequest<any>, next: HttpHandler) {
let authservice = this.injector.get(AuthService)
let tokenreq = req.clone({
setHeaders: {
Authorization: `Bearer ${authservice.setToken()}`
}
})
return next.handle(tokenreq).pipe(
catchError((error) => {
if (error.error.message == 'The incoming token has expired') {
authservice.renewToken()
let tokenreq = req.clone({
setHeaders: {
Authorization: `Bearer ${authservice.setToken()}`
}
})
return next.handle(tokenreq)
}
else return throwError(error)
})
);
}
}
intercept(请求:HttpRequest,下一步:HttpHandler){
让authservice=this.injector.get(authservice)
让tokenreq=req.clone({
集合标题:{
授权:`Bearer${authservice.setToken()}`
}
})
返回next.handle(tokenreq).pipe(
catchError((错误)=>{
if(error.error.message=='传入令牌已过期'){
authservice.RenewatToken()
让tokenreq=req.clone({
集合标题:{
授权:`Bearer${authservice.setToken()}`
}
})
返回next.handle(tokenreq)
}
else返回投掷器(错误)
})
);
}
}
问题是在我收到过期的令牌消息后,authservice.renewToken()
和authservice.setToken()
同时被调用,因此再次设置过期的令牌
另一个问题是,如果用户在cookie中再次打开应用程序并使用过期的令牌,那么所有的
GET
方法都将抛出错误并多次请求新令牌。如何处理过期令牌错误?您可以通过使用retryWhen
运算符将setToken
连接到返回的可观察对象来修复此故障行为。
这样,renewToken
和setToken
将不会并行执行,更重要的是,setToken
将由拦截器链在每个请求中考虑
intercept(req: HttpRequest<any>, next: HttpHandler) {
const authservice = this.injector.get(AuthService);
return of(req).pipe(
switchMap((req) => {
return authservice.setToken() // Gets the token. *should rename this method to getToken()
.pipe(
map(token => { // Set the token.
const tokenreq = req.clone({
setHeaders: {
Authorization: `Bearer ${authservice.setToken()}`
}
});
return tokenreq;
})
),
switchMap(tokenreq => next.handle(tokenreq)), // Execute next interceptor and eventually send the request.
retryWhen(errors => errors.pipe(
mergeMap((err: HttpErrorResponse, i: number) => {
authservice.invalidateToken() // Invalidate token. Erase token or expires it.
if (error.error.message == 'The incoming token has expired') {
return of(err); // will start the current pipe all over again - and get the token once again.
}
return throwError(error);
})
)
)
}
在这个回答中:
1) interceptor method execution -> setToken() -> return observable
2) request asked by http.get(..) -> chain of observables return by interceptors and setToken() inside one! -> request sent -> chain of observables
注意:
setToken
方法应返回一个带有该标记的可观察对象,并且invalidateToken
应能够删除该标记
这可以通过以下方式轻松实现:
private token$: AsyncSubject<string>;
getToken(): Observable {
if (!token$) this.token$ = new AsyncSubject();
getTokenOperation.subscribe(t => {
this.token$.next(t);
this.token$.complete();
})
return this.token$.asObservable();
}
invalidateToken() {
this.token$ = null;
}
private-token$:AsyncSubject;
getToken():可观察{
如果(!token$)此.token$=新的AsyncSubject();
getTokenOperation.subscribe(t=>{
此.token$.next(t);
此.token$.complete();
})
返回此.token$.asObservable();
}
失效{
this.token$=null;
}
您需要传递新令牌
return next.handle(request).pipe(
map((event: HttpEvent<any>) => {
return this.eventCallSendBack(event);
}),
catchError((error: HttpErrorResponse) => {
if (error instanceof HttpErrorResponse) {
switch (error.status) {
case 401:
return this.handle401Error(request, next);
case 403:
//DO Want you want here.
throw error;
default:
throw error;
}
}
throw error;
})
);
您希望拥有和添加令牌fn:
private addToken(event: HttpRequest<any>, token: string) {
return event.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
}
private addToken(事件:HttpRequest,token:string){
return event.clone({
集合标题:{
授权:`Bearer${token}`
}
});
}
现在假设您的令牌已过期,您需要创建fn,它将从某个身份验证中获取新令牌
private handle401Error(
request: HttpRequest<any>,
next: HttpHandler
): Observable<any> {
return authServices
.refreshToken(
token //This is the old token to get the new.
)
.pipe(
map(jwt => {
return jwt;
}),
switchMap((jwt: any) => {
return next
.handle(this.addToken(request, jwt.token)) // Add token in responce
.pipe(
map((event: HttpEvent<any>) => {
return this.eventCallSendBack(event);
})
);
}),
catchError(err => {
return throwError(err);
})
);
}
private handle401错误(
请求:HttpRequest,
下一步:HttpHandler
):可见{
返回授权服务
.refreshToken(
令牌//这是获取新令牌的旧令牌。
)
.烟斗(
映射(jwt=>{
返回jwt;
}),
switchMap((jwt:any)=>{
下一个返回
.handle(this.addToken(request,jwt.token))//在response中添加令牌
.烟斗(
映射((事件:HttpEvent)=>{
返回此.eventCallSendBack(事件);
})
);
}),
catchError(err=>{
回程抛掷器(err);
})
);
}
Renewtoken和settoken是同步方法,对吗?我想是的。我还没有宣布它们是异步的。你能展示一下RenewatToken
的代码吗?你能使用吗?RenewatToken方法的具体功能是什么?
private addToken(event: HttpRequest<any>, token: string) {
return event.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
}
private handle401Error(
request: HttpRequest<any>,
next: HttpHandler
): Observable<any> {
return authServices
.refreshToken(
token //This is the old token to get the new.
)
.pipe(
map(jwt => {
return jwt;
}),
switchMap((jwt: any) => {
return next
.handle(this.addToken(request, jwt.token)) // Add token in responce
.pipe(
map((event: HttpEvent<any>) => {
return this.eventCallSendBack(event);
})
);
}),
catchError(err => {
return throwError(err);
})
);
}