Angular 11集成MSAL 2.5.8后登录弹窗重定向异常问题
Angular 11 + MSAL 2.5.8 弹窗登录后异常重定向问题
我在Angular 11项目中使用MSAL 2.5.8,通过canActivate: [MsalGuard]完成登录后,弹窗被重定向至http://localhost:4200/#code=0.AX...地址。参考Angular11 MSAL示例项目集成,相关代码如下:
app.module.ts
export function MSALInstanceFactory(): IPublicClientApplication { return new PublicClientApplication({ auth: { clientId: '...', authority: '...', redirectUri: 'http://localhost:4200', postLogoutRedirectUri: '/', navigateToLoginRequestUrl: true }, cache: { cacheLocation: BrowserCacheLocation.LocalStorage, storeAuthStateInCookie: isIE, // set to true for IE 11 }, system: { allowNativeBroker: false, // Disables WAM Broker loggerOptions: { loggerCallback, logLevel: LogLevel.Info, piiLoggingEnabled: false } } }); } export function MSALInterceptorConfigFactory(): MsalInterceptorConfiguration { const protectedResourceMap = new Map<string, Array<string>>(); protectedResourceMap.set('https://graph.microsoft.com/v1.0/me', ['user.read']); return { interactionType: InteractionType.Popup, protectedResourceMap }; } export function MSALGuardConfigFactory(): MsalGuardConfiguration { return { interactionType: InteractionType.Popup, authRequest: { scopes: ['user.read'] }, loginFailedRoute: '/login-failed' }; } ... providers: [ { provide: LocationStrategy, useClass: HashLocationStrategy },, TacheService, CookieService, { provide: REDUCER_TOKEN, useFactory: getReducers }, { provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true }, MatNativeDateModule, EnvServiceProvider, { provide: HTTP_INTERCEPTORS, useClass: MsalInterceptor, multi: true }, { provide: MSAL_INSTANCE, useFactory: MSALInstanceFactory }, { provide: MSAL_GUARD_CONFIG, useFactory: MSALGuardConfigFactory }, { provide: MSAL_INTERCEPTOR_CONFIG, useFactory: MSALInterceptorConfigFactory }, MsalService, MsalGuard, MsalBroadcastService ], bootstrap: [AppComponent, MsalRedirectComponent], // MsalRedirectComponent bootstrapped here })
app.component.ts
export class AppComponent implements OnInit, OnDestroy, AfterViewInit { title = ''; isIframe = false; loginDisplay = false; private readonly _destroying$ = new Subject<void>(); activeAccount: AccountInfo | null = null; constructor( private breakpointObserver: BreakpointObserver, private oauthService: OAuthService, private store: Store<AppState>, private router: Router, private authService: MsalService, private msalBroadcastService: MsalBroadcastService, @Inject(MSAL_GUARD_CONFIG) private msalGuardConfig: MsalGuardConfiguration, private location: Location ) {} ngOnInit(): void { const currentPath = this.location.path(); this.isIframe = BrowserUtils.isInIframe() && !window.opener && currentPath.indexOf("logout") < 0; this.setLoginDisplay(); this.msalBroadcastService.inProgress$ .pipe( filter((status: InteractionStatus) => status === InteractionStatus.None), takeUntil(this._destroying$) ) .subscribe(() => { this.setLoginDisplay(); this.checkAndSetActiveAccount(); }) } checkAndSetActiveAccount(){ let activeAccount = this.authService.instance.getActiveAccount(); if (!activeAccount && this.authService.instance.getAllAccounts().length > 0) { let accounts = this.authService.instance.getAllAccounts(); this.authService.instance.setActiveAccount(accounts[0]); } } setLoginDisplay() { this.loginDisplay = this.authService.instance.getAllAccounts().length > 0; } loginRedirect() { if (this.msalGuardConfig.authRequest){ this.authService.loginRedirect({...this.msalGuardConfig.authRequest} as RedirectRequest); } else { this.authService.loginRedirect(); } } loginPopup() { if (this.msalGuardConfig.authRequest){ this.authService.loginPopup({...this.msalGuardConfig.authRequest} as PopupRequest) .subscribe((response: AuthenticationResult) => { this.authService.instance.setActiveAccount(response.account); }); } else { this.authService.loginPopup() .subscribe((response: AuthenticationResult) => { this.authService.instance.setActiveAccount(response.account); }); } }
app-routing.module.ts
const routes: Routes = [ { path: 'profile', component: ProfileComponent, canActivate: [MsalGuard] }, { // Needed for hash routing path: 'error', component: HomeComponent }, { // Needed for hash routing path: 'state', component: HomeComponent }, { // Needed for hash routing path: 'code', component: HomeComponent }, { path: '', component: HomeComponent, canActivate: [MsalGuard] }, ]; const initialNavigation = (!BrowserUtils.isInIframe() && !BrowserUtils.isInPopup()) || window.location.href.indexOf("logout") > 0; // Remove this line to use Angular Universal @NgModule({ imports: [RouterModule.forRoot(routes, { useHash: true, // Don't perform initial navigation in iframes or popups, except for logout initialNavigation: initialNavigation ? 'enabled' : 'disabled' // Remove this line to use Angular Universal })], exports: [RouterModule] }) export class AppRoutingModule {}
访问https://localhost:4200/#/profile时,弹窗出现上述异常重定向情况。
解决办法
修正RedirectUri配置
由于项目使用哈希路由,需将redirectUri修改为带哈希后缀的地址,让MSAL正确识别路由结构:// 在MSALInstanceFactory的auth配置中修改 redirectUri: 'http://localhost:4200/#',关闭navigateToLoginRequestUrl
弹窗登录场景下,该配置会导致MSAL尝试跳转回登录前的请求URL,引发参数混乱。修改配置:navigateToLoginRequestUrl: false优化初始导航逻辑
调整initialNavigation的判断条件,确保弹窗内的初始导航被正确禁用,避免路由错误解析code参数:const initialNavigation = !BrowserUtils.isInPopup() && !BrowserUtils.isInIframe() || window.location.href.includes('logout');分离弹窗与重定向流处理
当前项目同时启用了弹窗交互和MsalRedirectComponent,可能引发冲突。若主要使用弹窗登录,可移除MsalRedirectComponent的bootstrap配置;若需保留,需确保弹窗回调不会被重定向组件干扰。
内容的提问来源于stack exchange,提问作者Cédric
相关产品推荐
相关产品推荐

