Angular中MSALService登录请求无法触发LoaderService加载组件问题
问题描述
我正在开发一款需使用微软凭证登录的Angular应用,同时使用Http拦截器在HttpClient发起请求时显示加载组件。当前问题是:登录时MSALService发起的请求无法触发加载组件,应用在MSAL配置请求完成前看似处于冻结状态。
拦截器代码
import {Injectable} from '@angular/core'; import {Observable} from 'rxjs'; import {finalize} from 'rxjs/operators'; import {LoaderService} from './loader.service'; import { HttpEvent, HttpHeaders,HttpHandler, HttpInterceptor, HttpRequest, HttpClient,HttpParams,HttpResponse,HttpErrorResponse } from '@angular/common/http'; @Injectable({ providedIn: 'root' }) export class InterceptorService implements HttpInterceptor { service_count = 0; // initialize the counter. constructor(public loaderService: LoaderService) { } intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { this.service_count++; this.loaderService.is_loading.next(true); return next.handle(req).pipe( finalize( () => { this.service_count--; if (this.service_count === 0) { this.loaderService.is_loading.next(false); } } ) ); } }
Loader Service代码
import { Injectable } from '@angular/core'; import {BehaviorSubject} from "rxjs"; @Injectable({ providedIn: 'root' }) export class LoaderService { public is_loading: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false); constructor() { } }
解决方案
MSAL Service内部发起的请求并未通过Angular的HttpClient,而是直接使用浏览器原生的fetch或XMLHttpRequest,因此Http拦截器无法捕获这些请求。可通过以下两种方式解决:
方式一:监听MSAL生命周期事件
MSAL Angular提供了生命周期事件,通过订阅这些事件可控制加载组件的显示与隐藏:
- 在登录组件或核心模块中注入
MsalService并订阅事件:
import { MsalService, EventType } from '@azure/msal-angular'; constructor(private msalService: MsalService, private loaderService: LoaderService) { this.msalService.instance.addEventCallback((event) => { // 登录/获取令牌请求开始时显示加载 if (event.eventType === EventType.LOGIN_START || event.eventType === EventType.ACQUIRE_TOKEN_START) { this.loaderService.is_loading.next(true); } // 请求结束(成功/失败)时隐藏加载 const endEvents = [ EventType.LOGIN_SUCCESS, EventType.LOGIN_FAILURE, EventType.ACQUIRE_TOKEN_SUCCESS, EventType.ACQUIRE_TOKEN_FAILURE ]; if (endEvents.includes(event.eventType)) { this.loaderService.is_loading.next(false); } }); }
- 组件销毁时取消订阅,避免内存泄漏:
import { Subscription } from 'rxjs'; private eventSubscription?: Subscription; ngOnInit(): void { this.eventSubscription = this.msalService.instance.addEventCallback((event) => { // 上述事件处理逻辑 }); } ngOnDestroy(): void { this.eventSubscription?.unsubscribe(); }
方式二:自定义MSAL的HTTP客户端
让MSAL请求通过Angular的HttpClient发送,这样拦截器就能正常捕获请求:
- 创建自定义HTTP客户端类,实现
IMsalHttpClient:
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { IMsalHttpClient } from '@azure/msal-angular'; @Injectable() export class CustomMsalHttpClient implements IMsalHttpClient { constructor(private httpClient: HttpClient) {} sendRequest<T>(url: string, options: any): Promise<T> { return this.httpClient.request(options.method || 'GET', url, options).toPromise(); } }
- 在
app.module.ts中配置MSAL时替换默认HTTP客户端:
import { MsalModule, IMsalHttpClient } from '@azure/msal-angular'; import { CustomMsalHttpClient } from './custom-msal-http-client'; @NgModule({ imports: [ MsalModule.forRoot({ auth: { clientId: '你的客户端ID', authority: '你的权限地址', redirectUri: '你的重定向URI' } }) ], providers: [ { provide: IMsalHttpClient, useClass: CustomMsalHttpClient } ] }) export class AppModule { }
内容的提问来源于stack exchange,提问作者FranciscoPoloV
相关产品推荐
相关产品推荐

