每个教程和代码片段都使用这种刷新令牌代码:https://gist.github.com/abereghici/054cefbdcd8ccd3ff03dcc4e5155242b,它在我的示例中根本无法工作,因为this.authService.refreshToken()
执行HTTP请求,在.subscribe()
生成之前不会执行调用。当我添加订阅调用时,它会在一个新请求中调用http post,但这在我的脑海中是杂乱无章的。你能不能解释一下,告诉我如何正确处理这件事?请不要把我见过的片段连在一起。
有关我的ASP.NET Core2.2WebAPI后端的信息:
catchError()
。this.authService.logout()
上也会有http请求,即使它不在我下面提供的代码中。auth.interceptor.ts
import { Injectable } from '@angular/core';
import {
HttpEvent,
HttpInterceptor,
HttpHandler,
HttpRequest,
HttpErrorResponse
} from '@angular/common/http';
import { Observable, throwError, BehaviorSubject } from 'rxjs';
import { catchError, switchMap } from 'rxjs/operators';
import { AuthService } from '../services/auth.service';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
private refreshTokenInProgress = false;
private tokenSubject = new BehaviorSubject<any>(null);
constructor(private authService: AuthService) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request)
.pipe(
catchError((error: HttpErrorResponse) => {
if (error instanceof HttpErrorResponse) {
if (error.status === 401) {
return this.handleHttpResponseError(request, next);
}
}
return throwError(error);
})
);
}
private handleHttpResponseError(request: HttpRequest<any>, next: HttpHandler) {
const accessToken = this.authService.getJwtToken();
// if jwt token is not set, we just let the request execute
if (!accessToken) {
return next.handle(request);
}
// if jwt token has not expired yet, we add the authorize header
// otherwise we refresh the token
if (!this.authService.isTokenExpired()) {
console.log('added authorization to the headers')
return next.handle(this.attachTokenToRequest(request, accessToken));
} else {
console.log('token expired');
this.authService.refreshToken()
.pipe(
switchMap(result => {
console.log(`API returned: ${result}`);
return next.handle(this.attachTokenToRequest(request, accessToken));
})
);
return next.handle(request);
}
}
private attachTokenToRequest(request: HttpRequest<any>, token: string) {
return request.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
}
}
auth.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from 'src/environments/environment';
import { map } from 'rxjs/operators';
import { JwtHelperService } from '@auth0/angular-jwt';
import { AccessToken } from '../types/user';
@Injectable()
export class AuthService {
private actionUrl: string;
private readonly JWT_TOKEN = 'access_token';
private readonly REFRESH_TOKEN = 'refresh_token';
constructor(private httpClient: HttpClient) {
this.actionUrl = `${environment.baseUrls.server}api/auth`;
}
isLoggedIn(): boolean {
return !!this.getJwtToken();
}
login(credentials: { email: string, password: string }) {
return this.httpClient.post<AccessToken>(`${this.actionUrl}/login`, credentials)
.pipe(
map(tokens => {
this.setJwtToken(tokens.accessToken);
this.setRefreshToken(tokens.refreshToken);
return true;
})
);
}
refreshToken() {
console.log('refreshToken() called');
const helper = new JwtHelperService();
const email = helper.decodeToken(this.getJwtToken()).sub;
return this.httpClient.post<AccessToken>(`${this.actionUrl}/token/refresh`, { 'refreshToken': localStorage.getItem(this.REFRESH_TOKEN), 'email': email })
.pipe(
map(tokens => {
console.log('refreshToken().pipe called()');
this.setJwtToken(tokens.accessToken);
this.setRefreshToken(tokens.refreshToken);
return true;
})
);
}
logout() {
localStorage.removeItem(this.JWT_TOKEN);
localStorage.removeItem(this.REFRESH_TOKEN);
}
isTokenExpired(): boolean {
const helper = new JwtHelperService();
return helper.isTokenExpired(this.getJwtToken());
}
getJwtToken(): string {
return localStorage.getItem(this.JWT_TOKEN);
}
setJwtToken(token: string) {
localStorage.setItem(this.JWT_TOKEN, token);
}
getRefreshToken(): string {
return localStorage.getItem(this.REFRESH_TOKEN);
}
setRefreshToken(token: string) {
localStorage.setItem(this.REFRESH_TOKEN, token);
}
}
发布于 2019-09-15 12:40:44
我认为问题就在这里:
else {
console.log('token expired');
// Here!!!
this.authService.refreshToken()
.pipe(
switchMap(result => {
console.log(`API returned: ${result}`);
return next.handle(this.attachTokenToRequest(request, accessToken));
})
);
return next.handle(request);
}
}
返回从authService.refreshToken.返回的可观察到的,而不是
您必须确保返回它,以便使其成为main stream
的一部分,这意味着如果一个观察者订阅了,那么main stream
也会被订阅。
我创建了一个StackBlitz实例来说明如何在一个流中包含多个可观察到的内容,以及当订阅“主”流时它们都是如何被订阅的。
因此,我认为(并希望)这将解决你的问题:
else {
console.log('token expired');
return this.authService.refreshToken()
.pipe(
switchMap(result => {
console.log(`API returned: ${result}`);
return next.handle(this.attachTokenToRequest(request, accessToken));
})
);
}
}
https://stackoverflow.com/questions/57943479
复制相似问题