说明
基于angular拦截器实现,接口报401错误时(一般情况下是token过期了)自动刷新token,避免用户在长时间未关闭页面时导致的授权过期问题
代码
import {
HttpErrorResponse,
HttpEvent,
HttpHandler,
HttpInterceptor,
HttpRequest
} from "@angular/common/http";
import {
Injectable
} from "@angular/core";
import {
throwError,
Observable,
BehaviorSubject,
of
} from 'rxjs';
import {
catchError,
filter,
take,
switchMap,
mergeMap,
finalize
} from 'rxjs/operators';
import {
serviceType
} from "src/app/core/services/data-inquire/cus-type";
import {
DataInquireFuncService
} from "src/app/core/services/data-inquire/data-inquire-func.service";
import {
ComFuncService
} from "../com.func.service";
@Injectable({
providedIn: 'root'
})
export class ServiceAuthInterceptor implements HttpInterceptor {
// 应用代码,按需修改
authToken = '';
// 排除拦截的关键字段,按需修改(高优先级)
excludeList = [
'login', 'RefreshToken'
]
// 拦截地址的关键字段,按需修改
interceptorList = [
'geodaapi',
'192.168.3.46:6360',
'192.168.3.119:6360'
];
private refreshTokenInProgress = false;
private refreshTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);
constructor(
private comFuncService: ComFuncService,
private dataInquireFuncService: DataInquireFuncService
) { }
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
// 判断是否需要拦截
if (this.excludeList.length) {
for (let i = 0; i < this.excludeList.length; i++) {
if (req.url.indexOf(this.excludeList[i]) > -1) {
return next.handle(req);
}
}
}
// 添加授权Token
req = this.addAuthToken(req);
return next.handle(req).pipe(
catchError((err: HttpErrorResponse) => {
if (err && err.status === 401) {
if (this.refreshTokenInProgress) {
return this.refreshTokenSubject.pipe(
filter(result => result !== null),
take(1),
switchMap(() => next.handle(this.addAuthToken(req)))
);
} else {
this.refreshTokenInProgress = true;
// 设置 refreshTokenSubject 为 null,这样随后的 API 将等到新的 token 被取回时才调用。
this.refreshTokenSubject.next(null);
return this.refreshToken().pipe(
switchMap((success: boolean) => {
this.refreshTokenSubject.next(success);
return next.handle(this.addAuthToken(req));
}),
// 当我们调用刷新 token 方法完成时,重置 refreshTokenInProgress 为 false,
// 这是为了下次 token 需要再次被刷新
finalize(() => this.refreshTokenInProgress = false)
);
}
}
throw err;
})
);
}
/**
* @description: 刷新token
* @param {*}
* @return {*}
*/
refreshToken() {
// 获取用于获取新token的refreshToken值
const refreshToken = this.comFuncService.getRefreshToken();
// 通过http方法请求接口获取新的有效的token
return this.dataInquireFuncService.request(serviceType.INIT, 'login', 'refreshToken', {
params: {
refreshToken: refreshToken
}
}).pipe(mergeMap((res: any) => {
if (res && res.code === 1) {
const tokenInfo = res.data;
sessionStorage.setItem('tokenInfo', JSON.stringify(tokenInfo));
return of(true);
}
return of(false);
}))
}
/**
* @description: 添加授权Token
* @param {HttpRequest} req
* @return {*}
*/
addAuthToken(req: HttpRequest<any>) {
// 获取token
this.authToken = this.comFuncService.getToken();
// 拦截追加
let authToken = null;
const requestUrl = req.url.toString();
// 循环判断,按需增加token
for (let i = 0; i < this.interceptorList.length; i++) {
const key = this.interceptorList[i];
if (requestUrl.indexOf(key) !== -1) {
authToken = 'Bearer ' + this.authToken;
break;
}
}
if (authToken) {
req = req.clone({
setHeaders: {
'Authorization': authToken
}
});
}
return req;
}
}