iPhone设备Angular应用使用MSAL登录时出现interaction_in_progress错误
问题背景
使用@azure/msal-angular和@azure/msal-browser实现Angular应用登录功能时,仅iPhone设备触发以下控制台异常:
Uncaught (in promise) BrowserAuthError: interaction_in_progress: Interaction is currently in progress. Please ensure that this interaction has been completed before calling an interactive API.
Android及其他设备运行正常,登录数据可正常返回,但iPhone上的异常影响体验。已尝试更新MSAL版本、切换loginRedirect替代loginPopup,问题依旧,此前iPhone设备上运行正常。
登录核心代码如下:
login(userFlowRequest?: RedirectRequest | PopupRequest) { localStorage.clear(); sessionStorage.clear(); if (this.msalGuardConfig.interactionType === InteractionType.Popup) { if (this.msalGuardConfig.authRequest) { this.authService .loginPopup({ ...this.msalGuardConfig.authRequest, ...userFlowRequest, } as PopupRequest) .subscribe((response: AuthenticationResult) => { this.authService.instance.setActiveAccount(response.account); }); } else { this.authService .loginPopup(userFlowRequest) .subscribe((response: AuthenticationResult) => { this.authService.instance.setActiveAccount(response.account); }); } } else { if (this.msalGuardConfig.authRequest) { this.authService.loginRedirect({ ...this.msalGuardConfig.authRequest, ...userFlowRequest, } as RedirectRequest); } else { this.authService.loginRedirect(userFlowRequest); } } }
解决方案
1. 阻止登录方法重复触发
iPhone Safari在快速点击、触摸/点击事件双重触发场景下,可能导致login方法被多次调用,MSAL检测到已有交互进程后报错。添加防重复点击锁:
isLoggingIn = false; login(userFlowRequest?: RedirectRequest | PopupRequest) { if (this.isLoggingIn) return; this.isLoggingIn = true; // 原登录逻辑... // Popup模式下,在订阅的完成/错误回调重置状态 this.authService.loginPopup(request) .subscribe({ next: (res) => { this.authService.instance.setActiveAccount(res.account); }, complete: () => { this.isLoggingIn = false; }, error: () => { this.isLoggingIn = false; } }); // Redirect模式下,页面跳转后会刷新,可在AppComponent的ngOnInit中重置isLoggingIn }
2. 清理MSAL交互状态残留
MSAL会在sessionStorage中存储交互状态(如msal.interaction.status),若之前的交互异常终止(如页面意外刷新、弹窗被拦截),会导致状态残留引发误判。在登录前主动清理:
login(userFlowRequest?: RedirectRequest | PopupRequest) { // 仅清理MSAL交互相关状态,避免影响其他存储数据 sessionStorage.removeItem('msal.interaction.status'); sessionStorage.removeItem('msal.interaction.request'); // 原登录逻辑... }
3. 适配Safari隐私政策限制
近期Safari的跨站跟踪阻止、隐私模式可能导致MSAL状态存储异常,调整MSAL缓存配置:
MsalModule.forRoot(new PublicClientApplication({ auth: { clientId: '你的clientId', authority: '你的authority' }, cache: { location: 'LocalStorage', // 替换默认的SessionStorage,适配Safari隐私模式 storeAuthStateInCookie: true // 开启Cookie存储作为 fallback,避免状态丢失 } }))
4. 优化路由守卫逻辑
若使用MsalGuard,iPhone上可能因路由跳转触发多次守卫检查,导致重复登录。在守卫中先检查活跃账户:
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> { return this.authService.instance.getActiveAccount() ? of(true) : this.authService.loginRedirect({ redirectUri: state.url }); }
修改后的完整登录示例
isLoggingIn = false; login(userFlowRequest?: RedirectRequest | PopupRequest) { if (this.isLoggingIn) return; this.isLoggingIn = true; // 清理MSAL交互状态残留 sessionStorage.removeItem('msal.interaction.status'); sessionStorage.removeItem('msal.interaction.request'); if (this.msalGuardConfig.interactionType === InteractionType.Popup) { const request = this.msalGuardConfig.authRequest ? { ...this.msalGuardConfig.authRequest, ...userFlowRequest } as PopupRequest : userFlowRequest; this.authService.loginPopup(request) .subscribe({ next: (response: AuthenticationResult) => { this.authService.instance.setActiveAccount(response.account); }, complete: () => { this.isLoggingIn = false; }, error: () => { this.isLoggingIn = false; } }); } else { const request = this.msalGuardConfig.authRequest ? { ...this.msalGuardConfig.authRequest, ...userFlowRequest } as RedirectRequest : userFlowRequest; this.authService.loginRedirect(request); } }
内容的提问来源于stack exchange,提问作者Engr Ejaz Ashraf

