【发布时间】:2017-12-25 21:34:21
【问题描述】:
身份验证服务未在刷新令牌时注销 401 错误。相反,它转到 catchError.ts。应用程序如何处理这个问题。
场景 1.最初使用基本授权标头获取访问令牌。 2. 使用访问令牌进行服务器调用。 3.一旦访问toekn过期,调用刷新令牌服务。 4. 刷新令牌调用成功后,将新令牌用于其余的服务调用。 5. 刷新toeken失败,会返回401错误,但应用程序无法捕捉到错误并且永远不会退出。
使用 Angular 4 Http 拦截器
这是拦截器
import { Injectable, Injector } from '@angular/core';
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpResponse, HttpErrorResponse, HttpClient} from '@angular/common/http';
import * as AppUtils from '../common/app.utils';
import { AuthService } from './auth.service';
import {Observable} from 'rxjs/Rx';
import {
Router,
Event,
NavigationStart, RoutesRecognized, NavigationEnd, NavigationCancel, NavigationError
} from '@angular/router'
import { LoaderService } from '../loader/loader.service'
import { BehaviorSubject } from "rxjs/BehaviorSubject";
import { ErrorObservable } from 'rxjs/observable/ErrorObservable';
import { EmptyObservable } from 'rxjs/observable/EmptyObservable';
import { catchError, filter, take, switchMap, finalize } from "rxjs/operators";
import { SharedService } from '../common/services/shared.service';
declare var swal: any;
@Injectable()
export class TokenInterceptor implements HttpInterceptor {
isRefreshingToken: boolean = true;
tokenSubject: BehaviorSubject<string> = new BehaviorSubject<string>(null);
constructor(private inj: Injector, private router: Router) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const auth = this.inj.get(AuthService)
return next.handle(this.addToken(request))
.pipe(
catchError((error, ca) => {
if (error instanceof HttpErrorResponse) {
switch ((<HttpErrorResponse>error).status) {
case 401:
return this.handle401Error(request, next, auth)
default:
return ErrorObservable.create(error);
}
} else {
return ErrorObservable.create(error);
}
})
)
}
addToken(req: HttpRequest<any>): HttpRequest<any> {
let customReq: any;
let client_id = 'test';
let client_secret= 'secret';
let basicheader = btoa(client_id +':'+ client_secret);
if(req.url.indexOf("token?grant_type") < 0 || req.url.indexOf("token?grant_type") == 0){
customReq = req.clone({
headers: req.headers.set('Content-Type', 'application/json')
.set('Authorization','Bearer '+ localStorage.getItem(AppUtils.STORAGE_ACCOUNT_ACCESS_TOKEN))
})
//Set estCode and perscode for Alshif Users
if(localStorage.getItem(AppUtils.ALSHIFA_TRUSTED_LOGIN)!=null && localStorage.getItem(AppUtils.ALSHIFA_TRUSTED_LOGIN)==="Y"){
req.headers.append(AppUtils.ALSHIFA_USER_INFO, localStorage.getItem(AppUtils.DEFAULT_INSTITUTE) +":"+
localStorage.getItem(AppUtils.PERSON_CODE));
}
}else{
customReq = req.clone({
headers: req.headers.set('Authorization','Basic '+ basicheader)
})
}
return customReq;
}
handle400Error(error) {
console.log("400 error");
if (error && error.status === 400 && error.error && error.error.error === 'invalid_grant') {
// If we get a 400 and the error message is 'invalid_grant', the token is no longer valid so logout.
return this.logoutUser();
}
return EmptyObservable.create();
}
handle401Error(req: HttpRequest<any>, next: HttpHandler, auth : any) {
if (this.isRefreshingToken) {
this.isRefreshingToken = false;
let customReq: any;
let client_id = 'test';
let client_secret= 'secret';
let basicheader = btoa(client_id +':'+ client_secret);
auth.refreshToken().subscribe((token) => {
console.log("token " +JSON.stringify(token));
if (token instanceof HttpErrorResponse) {
if (token.status === 401) {
console.log("error");
}
}
if (token) {
localStorage.setItem(AppUtils.STORAGE_ACCOUNT_ACCESS_TOKEN, token["access_token"]);
localStorage.setItem(AppUtils.STORAGE_ACCOUNT_REFRESH_TOKEN, token["refresh_token"]);
localStorage.setItem(AppUtils.STORAGE_ACCOUNT_EXPIRES_IN, token["expires_in"]);
this.tokenSubject.next(token["access_token"]);
return next.handle(this.addToken(req));
}
console.log("refresh failed");
// If we don't get a new token, we are in trouble so logout.
this.logoutUser();
return EmptyObservable.create();
}, (err) => {
console.log("error 2" +err);
// If there is an exception calling 'refreshToken', bad news so logout.
this.logoutUser();
return EmptyObservable.create();
},() => {
console.log("token finally)");
this.isRefreshingToken = true;
});
// )
} else {
console.log("this.tokenSubject "+ this.tokenSubject);
console.log("this.tokenSubjec2 "+ this.tokenSubject.filter(token => token != null));
return this.tokenSubject
.filter(token => token != null)
.take(1)
.switchMap(token => {
return next.handle(this.addToken(req));
});
}
}
logoutUser(){
swal({
title: 'Session Expired',
text: 'your session has been expired please re login',
timer: 5000,
onOpen: () => {
swal.showLoading()
}
}).then((result) => {
if (result.dismiss === 'timer') {
this.router.navigate([AppUtils.BACKEND_API_AUTHENTICATE_PATH]);
window.location.reload();
}
})
localStorage.clear();
this.router.navigate([AppUtils.BACKEND_API_AUTHENTICATE_PATH]);
// window.location.reload();
//return Observable.throw("");
}
这是认证服务类
import { Injectable, Component, EventEmitter } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpClient, HttpResponse, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
import 'rxjs/add/operator/map';
import {Observable} from 'rxjs/Rx';
import 'rxjs/add/operator/retry';
import * as AppUtils from '../common/app.utils';
import { Router } from '@angular/router';
import { SharedService } from '../common/services/shared.service';
import 'rxjs/add/operator/catch';
declare var swal: any;
@Injectable()
export class AuthService {
cachedRequests: Array<HttpRequest<any>> = [];
constructor(private router: Router, private http : HttpClient) {
}
refreshToken(): Observable<any>{
let client_id = 'irsauth';
let client_secret= 'secret';
let basicheader = btoa(client_id +':'+ client_secret);
let headers = new HttpHeaders();
headers.set('Authorization', 'Basic ' + basicheader);
return this.http.get(AppUtils.REFRESH_TOKEN + localStorage.getItem(AppUtils.STORAGE_ACCOUNT_REFRESH_TOKEN), { headers: headers })
.catch((e: any) => Observable.throw(this.errorHandler(e)))
}
errorHandler(error: any): void {
console.log("auth error")
Observable.throw("");
}
logoutUser(){
localStorage.clear();
this.router.navigate([AppUtils.BACKEND_API_AUTHENTICATE_PATH]);
// window.location.reload();
//return Observable.throw("");
}
}
}
【问题讨论】:
标签: angular typescript