说明
基于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);}}}// 添加授权Tokenreq = 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方法请求接口获取新的有效的tokenreturn 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>) {// 获取tokenthis.authToken = this.comFuncService.getToken();// 拦截追加let authToken = null;const requestUrl = req.url.toString();// 循环判断,按需增加tokenfor (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;}}
