具有 refresh_token 的 Angular5 Http 拦截器
Angular5 Http Interceptor with refresh_token
我正在尝试在我的 Angular5 中的 Http 拦截器中实现 access_token/refresh_token。我遇到的问题是在获得刷新令牌后无法再次调用。
因此,当我收到 401 错误(access_token 已过期)时,我使用 refresh_token 得到了一个新的 access_token,并且一切正常,直到这里。接下来,我应该使用新的 access_token 再次进行初始调用,因此我尝试使用第二个
进行此操作
return next.handle(req);
但这不起作用。因此,当我第一次单击并且令牌已过期时,应用程序成功获取了一个新令牌并将其写入 localStorage,但不会再次进行初始调用。如果我再次单击,则初始调用将成功进行(使用在上一次单击时正确存储的新访问令牌)。就像我无法摆脱困境一样。也许我犯了一个愚蠢的错误。
以下是我的 code.Please 建议。谢谢!
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<any> {
let access_token, refresh_token;
if (localStorage.currentUser) {
access_token = JSON.parse(localStorage.currentUser).access_token;
refresh_token = JSON.parse(localStorage.currentUser).refresh_token;
if(access_token){
req = req.clone({ headers: req.headers.set('Authorization', 'Bearer ' + access_token) });
}
}
return next.handle(req)
.catch((error, caught) => {
if (this.isAuthError(error)) {
return this._auth.getRefreshToken().map((resp) => {
let user = resp.json();
localStorage.setItem('currentUser', JSON.stringify(user));
access_token = JSON.parse(localStorage.currentUser).access_token;
req = req.clone({ headers: req.headers.set('Authorization', 'Bearer ' + access_token) });
return next.handle(req);
});
} else {
return Observable.throw(error);
}
})
}
在你的拦截中你需要设置 headers.
if(access_token){
req = req.clone({setHeaders:
{Authorization: `Bearer ${access_token}`}
});
}
您需要对另一个令牌执行相同的操作。
我做了类似的事情:
if ( this._auth.isValidToken() )
token = this._auth.getValidToken();
req = this.addToken(req, this._auth.getToken());
return next.handle(req);
}
// The getNewAccessToken is an observable
return this._auth.getNewAccessToken().pipe(switchMap(() => {
const clone: HttpRequest<any> = this.addToken(req, this._auth.getToken());
return next.handle(clone);
})).catch(error => {
if ( error.error === 'invalid_token' ) { // if it fails to refresh the token
// Redirect to Login, but you could also cache the url
this.router.navigate(['/login']);
return Observable.throw('Login expired');
}
console.log(error);
return Observable.throw(error);
});
get NewAccessToken() 函数如下所示:
public getNewAccessToken(): Observable<string> {
const headers = new HttpHeaders()
.set('Content-Type', 'application/x-www-form-urlencoded') // FIXME: Replace Encoded Base64 for a custom version
.set('Authorization', 'Basic WQQPWEOIRUPOIUQ=');
const params = new HttpParams().set('grant_type', 'refresh_token');
const httpOptions = { headers: headers, params: params, withCredentials: true };
return this.httpClient.post( this.oauthTokenUrl, new FormData(), httpOptions )
.map(success => {
this.storeToken(success['access_token']);
})
.catch(this.handleError);
}
商店Token功能:
public storeToken(token: string) {
this.jwtPayload = this.jwtHelper.decodeToken(token);
localStorage.setItem('token', token);
this.subjectUser.next( { name: this.jwtPayload.name, email: this.jwtPayload.user_name } );
}
您需要使用 flatMap() 而不是 map() ,如下所示:
....
if (this.isAuthError(error)) {
return this._auth.getRefreshToken().flatMap((resp) => {
.... ^^^^^^^
here
否则你的解决方案对我来说看起来不错。
我正在尝试在我的 Angular5 中的 Http 拦截器中实现 access_token/refresh_token。我遇到的问题是在获得刷新令牌后无法再次调用。 因此,当我收到 401 错误(access_token 已过期)时,我使用 refresh_token 得到了一个新的 access_token,并且一切正常,直到这里。接下来,我应该使用新的 access_token 再次进行初始调用,因此我尝试使用第二个
进行此操作return next.handle(req);
但这不起作用。因此,当我第一次单击并且令牌已过期时,应用程序成功获取了一个新令牌并将其写入 localStorage,但不会再次进行初始调用。如果我再次单击,则初始调用将成功进行(使用在上一次单击时正确存储的新访问令牌)。就像我无法摆脱困境一样。也许我犯了一个愚蠢的错误。
以下是我的 code.Please 建议。谢谢!
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<any> {
let access_token, refresh_token;
if (localStorage.currentUser) {
access_token = JSON.parse(localStorage.currentUser).access_token;
refresh_token = JSON.parse(localStorage.currentUser).refresh_token;
if(access_token){
req = req.clone({ headers: req.headers.set('Authorization', 'Bearer ' + access_token) });
}
}
return next.handle(req)
.catch((error, caught) => {
if (this.isAuthError(error)) {
return this._auth.getRefreshToken().map((resp) => {
let user = resp.json();
localStorage.setItem('currentUser', JSON.stringify(user));
access_token = JSON.parse(localStorage.currentUser).access_token;
req = req.clone({ headers: req.headers.set('Authorization', 'Bearer ' + access_token) });
return next.handle(req);
});
} else {
return Observable.throw(error);
}
})
}
在你的拦截中你需要设置 headers.
if(access_token){
req = req.clone({setHeaders:
{Authorization: `Bearer ${access_token}`}
});
}
您需要对另一个令牌执行相同的操作。
我做了类似的事情:
if ( this._auth.isValidToken() )
token = this._auth.getValidToken();
req = this.addToken(req, this._auth.getToken());
return next.handle(req);
}
// The getNewAccessToken is an observable
return this._auth.getNewAccessToken().pipe(switchMap(() => {
const clone: HttpRequest<any> = this.addToken(req, this._auth.getToken());
return next.handle(clone);
})).catch(error => {
if ( error.error === 'invalid_token' ) { // if it fails to refresh the token
// Redirect to Login, but you could also cache the url
this.router.navigate(['/login']);
return Observable.throw('Login expired');
}
console.log(error);
return Observable.throw(error);
});
get NewAccessToken() 函数如下所示:
public getNewAccessToken(): Observable<string> {
const headers = new HttpHeaders()
.set('Content-Type', 'application/x-www-form-urlencoded') // FIXME: Replace Encoded Base64 for a custom version
.set('Authorization', 'Basic WQQPWEOIRUPOIUQ=');
const params = new HttpParams().set('grant_type', 'refresh_token');
const httpOptions = { headers: headers, params: params, withCredentials: true };
return this.httpClient.post( this.oauthTokenUrl, new FormData(), httpOptions )
.map(success => {
this.storeToken(success['access_token']);
})
.catch(this.handleError);
}
商店Token功能:
public storeToken(token: string) {
this.jwtPayload = this.jwtHelper.decodeToken(token);
localStorage.setItem('token', token);
this.subjectUser.next( { name: this.jwtPayload.name, email: this.jwtPayload.user_name } );
}
您需要使用 flatMap() 而不是 map() ,如下所示:
....
if (this.isAuthError(error)) {
return this._auth.getRefreshToken().flatMap((resp) => {
.... ^^^^^^^
here
否则你的解决方案对我来说看起来不错。