使用@azure/msal-angular 登录到 Azure B2C Angular 应用程序时发出问题

Issue logging into Azure B2C Angular application using @azure/msal-angular

我在使用 @azure/msal-angular 库使用 PKCE 的授权代码流将我的应用程序登录到 B2C 时遇到一个奇怪的错误。我正在重定向回 B2C 登录,被重定向回我的应用程序,我的应用程序成功地从令牌 api 获取了一个令牌,但随后记录了一个 JS 错误并阻止我的应用程序继续加载。这是控制台输出:

[Thu, 27 Jan 2022 22:34:53 GMT] : @azure/msal-angular@2.1.0 : Info - Interceptor - 1 scopes found for endpoint
msal-config.module.ts:27 [Thu, 27 Jan 2022 22:34:54 GMT] : @azure/msal-angular@2.1.0 : Info - Interceptor - 1 scopes found for endpoint
msal-config.module.ts:27 [Thu, 27 Jan 2022 22:34:54 GMT] : @azure/msal-angular@2.1.0 : Info - Interceptor - 1 scopes found for endpoint
msal-config.module.ts:27 [Thu, 27 Jan 2022 22:34:54 GMT] : @azure/msal-angular@2.1.0 : Info - Interceptor - 1 scopes found for endpoint
core.js:40853 Angular is running in the development mode. Call enableProdMode() to enable the production mode.
msal-config.module.ts:27 [Thu, 27 Jan 2022 22:34:54 GMT] : @azure/msal-browser@2.21.0 : Info - Emitting event: msal:handleRedirectStart
core.js:40853 Angular is running in the development mode. Call enableProdMode() to enable the production mode.
msal-config.module.ts:27 [Thu, 27 Jan 2022 22:34:54 GMT] : @azure/msal-angular@2.1.0 : Error - Interceptor - acquireTokenSilent rejected with error. Invoking interaction to resolve.
msal-config.module.ts:27 [Thu, 27 Jan 2022 22:34:54 GMT] : @azure/msal-browser@2.21.0 : Info - Emitting event: msal:loginStart
msal-config.module.ts:27 [Thu, 27 Jan 2022 22:34:54 GMT] : @azure/msal-angular@2.1.0 : Error - Interceptor - acquireTokenSilent rejected with error. Invoking interaction to resolve.
msal-config.module.ts:27 [Thu, 27 Jan 2022 22:34:54 GMT] : @azure/msal-browser@2.21.0 : Info - Emitting event: msal:loginStart
msal-config.module.ts:27 [Thu, 27 Jan 2022 22:34:54 GMT] : @azure/msal-angular@2.1.0 : Error - Interceptor - acquireTokenSilent rejected with error. Invoking interaction to resolve.
msal-config.module.ts:27 [Thu, 27 Jan 2022 22:34:54 GMT] : @azure/msal-browser@2.21.0 : Info - Emitting event: msal:loginStart
msal-config.module.ts:27 [Thu, 27 Jan 2022 22:34:54 GMT] : @azure/msal-angular@2.1.0 : Error - Interceptor - acquireTokenSilent rejected with error. Invoking interaction to resolve.
msal-config.module.ts:27 [Thu, 27 Jan 2022 22:34:54 GMT] : @azure/msal-browser@2.21.0 : Info - Emitting event: msal:loginStart
4msal-config.module.ts:27 [Thu, 27 Jan 2022 22:34:54 GMT] : @azure/msal-browser@2.21.0 : Info - Emitting event: msal:loginFailure
4core.js:6241 ERROR Error: 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.  For more visit: aka.ms/msaljs/browser-errors.
BrowserAuthError: interaction_in_progress: Interaction is currently in progress. Please ensure that this interaction has been completed before calling an interactive API.  For more visit: aka.ms/msaljs/browser-errors.
    at BrowserAuthError.AuthError [as constructor] (AuthError.js:27:1)
    at new BrowserAuthError (BrowserAuthError.js:169:1)
    at Function.push.../../node_modules/@azure/msal-browser/dist/error/BrowserAuthError.js.BrowserAuthError.createInteractionInProgressError (BrowserAuthError.js:236:1)
    at RedirectClient.<anonymous> (StandardInteractionClient.js:216:51)
    at step (_tslib.js:75:1)
    at Object.next (_tslib.js:56:45)
    at _tslib.js:49:1
    at new ZoneAwarePromise (zone-evergreen.js:960:1)
    at __awaiter (_tslib.js:45:1)
    at RedirectClient.push.../../node_modules/@azure/msal-browser/dist/interaction_client/StandardInteractionClient.js.StandardInteractionClient.preflightInteractiveRequest (StandardInteractionClient.js:207:25)
    at resolvePromise (zone-evergreen.js:798:1)
    at zone-evergreen.js:705:1
    at zone-evergreen.js:721:1
    at ZoneDelegate.invoke (zone-evergreen.js:364:1)
    at Object.onInvoke (core.js:41667:1)
    at ZoneDelegate.invoke (zone-evergreen.js:363:1)
    at Zone.run (zone-evergreen.js:123:1)
    at zone-evergreen.js:857:1
    at ZoneDelegate.invokeTask (zone-evergreen.js:399:1)
    at Object.onInvokeTask (core.js:41645:1)
defaultErrorLogger @ core.js:6241
handleError @ core.js:6294
next @ core.js:42627
schedulerFn @ core.js:37132
__tryOrUnsub @ Subscriber.js:183
next @ Subscriber.js:122
_next @ Subscriber.js:72
next @ Subscriber.js:49
next @ Subject.js:39
emit @ core.js:37092
(anonymous) @ core.js:41707
invoke @ zone-evergreen.js:364
run @ zone-evergreen.js:123
runOutsideAngular @ core.js:41501
onHandleError @ core.js:41704
handleError @ zone-evergreen.js:368
runGuarded @ zone-evergreen.js:136
api.microtaskDrainDone @ zone-evergreen.js:670
drainMicroTaskQueue @ zone-evergreen.js:576
Promise.then (async)
scheduleMicroTask @ zone-evergreen.js:552
scheduleTask @ zone-evergreen.js:388
onScheduleTask @ zone-evergreen.js:272
scheduleTask @ zone-evergreen.js:378
scheduleTask @ zone-evergreen.js:210
scheduleMicroTask @ zone-evergreen.js:230
scheduleResolveOrReject @ zone-evergreen.js:847
resolvePromise @ zone-evergreen.js:785
(anonymous) @ zone-evergreen.js:705
webpackJsonpCallback @ bootstrap:25
(anonymous) @ mcl-portal-order.js:1
capture_page_info.js:954 Gather controls: 2.934814453125 ms
msal-config.module.ts:27 [Thu, 27 Jan 2022 22:34:54 GMT] : [64b25cee-dd82-4679-8a9e-b4eb65289ff3] : @azure/msal-common@6.0.0 : Info - in acquireToken call
DevTools failed to load source map: Could not load content for chrome-extension://lkoeejijapdihgbegpljiehpnlkadljb/browser-polyfill.js.map: HTTP error: status code 404, net::ERR_UNKNOWN_URL_SCHEME
client:52 [WDS] Live Reloading enabled.
msal-config.module.ts:27 [Thu, 27 Jan 2022 22:34:54 GMT] : @azure/msal-browser@2.21.0 : Info - Emitting event: msal:loginSuccess
msal-config.module.ts:27 [Thu, 27 Jan 2022 22:34:54 GMT] : @azure/msal-browser@2.21.0 : Info - Emitting event: msal:handleRedirectEnd

如果在发生这种情况后刷新我的应用程序,应用程序可以正常加载并使用它获得的令牌适当地调用我的所有 api 端点。所以这只是 bootstraping 我的应用程序的初始过程,重定向到登录名,重定向回我的应用程序,发布令牌请求然后在收到令牌期间但在 api 提出要求?

我是不是配置错了?

我的 MsalConfigModule 设置了 MsalModule 的配置:

const isIE = window.navigator.userAgent.indexOf("MSIE ") > -1 || window.navigator.userAgent.indexOf("Trident/") > -1; // Remove this line to use Angular Universal
    
    export function loggerCallback(logLevel: LogLevel, message: string) {
      console.log(message);
    }
    
    export function MSALInstanceFactory(config: ConfigService): IPublicClientApplication {
    
      const authConf = config.getSettings()['oauthConfig'][0] as any;
    
      const authConfig = new PublicClientApplication({
        auth: {
          clientId: authConf['client_id'],
          authority: authConf.authority,
          knownAuthorities: [authConf.authority],
          redirectUri: authConf['redirect_uri'],
          postLogoutRedirectUri: authConf['redirect_uri'],
          navigateToLoginRequestUrl: true
        },
        cache:{
          cacheLocation: BrowserCacheLocation.SessionStorage,
          storeAuthStateInCookie: isIE
        },
        system: {
          loggerOptions: {
            loggerCallback,
            logLevel: LogLevel.Info,
            piiLoggingEnabled: false
          }
        }
      });
    
      return authConfig;
    }
    
    export function MSALInterceptorConfigFactory(config: ConfigService): MsalInterceptorConfiguration {
      const resourceMap = new Map<string, Array<string>>();
      // iterate over the urlMappings config and create a protectedresourcemap
      const configUrls = config.getSettings()['urlMappings'] as Array<any>;
      const scope = config.getSettings()['oauthConfig'][0].scope as string;
      configUrls.map(urlMap => resourceMap.set(`${urlMap.url}/*`, [scope]));
    
      return {
        interactionType: InteractionType.Redirect,
        protectedResourceMap: resourceMap
      };
    }
    
    export function MSALGuardConfigFactory(): MsalGuardConfiguration {
      return {
        interactionType: InteractionType.Redirect
      };
    }
    
    @NgModule({
      providers: [],
      imports: [MsalModule]
    })
    export class MsalConfigModule {
    
      static forRoot() {
        return {
          ngModule: MsalConfigModule,
          providers: [
            {
              provide: MSAL_INSTANCE,
              useFactory: MSALInstanceFactory,
              deps: [ConfigService]
            },
            {
              provide: MSAL_GUARD_CONFIG,
              useFactory: MSALGuardConfigFactory,
              deps: [ConfigService]
            },
            {
              provide: MSAL_INTERCEPTOR_CONFIG,
              useFactory: MSALInterceptorConfigFactory,
              deps: [ConfigService]
            },
            MsalService,
            MsalGuard,
            MsalBroadcastService,
            {
              provide: HTTP_INTERCEPTORS,
              useClass: MsalInterceptor,
              multi: true
            }
          ]
        };
      }
    }

我的主要应用程序模块的一部分:

@NgModule({
  declarations: [AppComponent],
  imports: [
    ...
    MsalConfigModule.forRoot()
  ],
  providers: [
    DatePipe,
    SlicePipe
  ],
  bootstrap: [AppComponent, MsalRedirectComponent],
})
export class AppModule {}

我的解决方案是添加

 canActivate:[MsalGuard]

守护我所有的路线。我认为潜在的问题是拦截器在我们有要发送的令牌之前正在寻找要在 api 请求中发送的令牌。添加守卫阻止路由激活,直到我们通过身份验证,然后一旦路由被激活,我的 api 请求就会触发,拦截器将有他们的令牌发送,一切正常。

我想采取的方法是你确实需要添加MsalGuard,提供拦截器和配置受保护的资源映射是不够的。