You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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时,弹窗出现上述异常重定向情况。


解决办法

  1. 修正RedirectUri配置
    由于项目使用哈希路由,需将redirectUri修改为带哈希后缀的地址,让MSAL正确识别路由结构:

    // 在MSALInstanceFactory的auth配置中修改
    redirectUri: 'http://localhost:4200/#',
    
  2. 关闭navigateToLoginRequestUrl
    弹窗登录场景下,该配置会导致MSAL尝试跳转回登录前的请求URL,引发参数混乱。修改配置:

    navigateToLoginRequestUrl: false
    
  3. 优化初始导航逻辑
    调整initialNavigation的判断条件,确保弹窗内的初始导航被正确禁用,避免路由错误解析code参数:

    const initialNavigation = !BrowserUtils.isInPopup() && !BrowserUtils.isInIframe() || window.location.href.includes('logout');
    
  4. 分离弹窗与重定向流处理
    当前项目同时启用了弹窗交互和MsalRedirectComponent,可能引发冲突。若主要使用弹窗登录,可移除MsalRedirectComponent的bootstrap配置;若需保留,需确保弹窗回调不会被重定向组件干扰。


内容的提问来源于stack exchange,提问作者Cédric

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 23:15:01