Недавно они выпустили библиотеку аутентификации Microsoft для JS. Я сам писал свои собственные httpIinterceptors, службу аутентификации и поток обработки. Это действительно работало!

Пока нация огня не напала.

Нет, просто прикалываюсь. Это работает, пока мне не нужно динамически загружать конфигурацию для MSAL. Ветка с проблемами на github началась здесь. В частности, мы обсудим, как получить вашу конфигурацию с сервера/API для загрузки вашего углового SPA.

Давайте углубимся в детали.

В этом потоке предлагается решение об использовании APP INITIALIZER для координации получения вашей конфигурации с использованием API. В какой-то момент документация MSAL указывает вам на использование конфигурации, как показано ниже, для внедрения в поставщиков APP MODULE.

providers: [    
    MsalService,
    {
      provide: APP_INITIALIZER,
      useFactory: initConfiguration,
      deps: [ConfigService],
      multi: true
    }, {
      provide: MSAL_CONFIG,
      useValue: getConfig()
    },    {
      provide: MSAL_Angular_CONFIG,
      useValue: getAngularConfig()
    },    
]

Если вы знакомы с настройками наших провайдеров в Angular, по сути, здесь происходит то, что функция useFactory и функция useValue вызываются одновременно. Итак, теперь вы должны координировать свои действия, чтобы в этом примере функция initConfiguration() вызывалась до getConfig() и getAngularConfig().

Вы можете делать некоторые причудливые трюки с наблюдаемыми/обещаниями и ждать, пока initConfiguration() скоординирует это. Его сложно писать и читать, особенно если вы не гуру в RXJS или у вас мало опыта в промисах.

Итак, давайте перейдем к реальному решению.

Перейдите к файлу main.ts в приложении. Это файл, который отвечает за загрузку вашего углового приложения в AppModule. Это будет выглядеть примерно так.

platformBrowserDynamic().bootstrapModule(AppModule)
      .catch(err => console.error(err));

Давайте обновим это, чтобы внедрить сюда наших пользовательских провайдеров.

platformBrowserDynamic([
      {
      provide: MSAL_CONFIG,
      useValue: getConfig()
    },    {
      provide: MSAL_Angular_CONFIG,
      useValue: getAngularConfig()
    },
    ]).bootstrapModule(AppModule)
      .catch(err => console.error(err));

Все, что вам нужно знать о платформе BrowserDynamic, это то, что вы можете установить своих собственных поставщиков до загрузки приложения.

Для этого примера давайте просто предположим, что мы будем собирать clientId, Authority и protectedResourceMap с нашего сервера для загрузки нашего приложения.

В нашем случае мы будем использовать 1 вызов API для получения всех трех этих свойств. Поскольку мы вызываем getConfig() и getAngularConfig(), нам нужно использовать некоторые приемы, чтобы этот единый API давал ответы на 2 разные функции. Давайте начнем здесь.

Насколько я знаю, мы не можем использовать угловой DI, потому что это все до того, как все это будет настроено. Мы сделаем наш http-клиент, как указано выше. Я использую RXJS pipe share(), чтобы поделиться ответом, возвращаемым с сервера. Я также преобразовываю наблюдаемое в обещание, потому что мне не нужно, чтобы наблюдаемое было открытым все время.

function MSALConfigFactory(): Configuration {
 return {
     auth: {
     clientId: clientId,
     authority: authority,
     validateAuthority: false,
     redirectUri: window.location.origin + ‘/’,
     postLogoutRedirectUri: window.location.origin + ‘/’,
     navigateToLoginRequestUrl: true,
     },
     cache: {
     cacheLocation: “localStorage”,
     storeAuthStateInCookie: isIE, // set to true for IE 11
    },
  };
}
function MSALAngularConfigFactory(): MsalAngularConfiguration {
    return {
    popUp: !isIE,
    consentScopes: ["scopes"],
    unprotectedResources: ["https://www.microsoft.com/en-us/"],
    protectedResourceMap,
    extraQueryParameters: {}
   };
}

Эта часть довольно проста, мы загрузили наши свойства конфигурации как для MSAL Config, так и для Angular Config. Далее, давайте используем наше обещание.

promise.then((x: any) => {
  clientId = x.auth.clientId
  authority = x.auth.authority
  protectedResourceMap = x.protectedResourceMap
platformBrowserDynamic([
{provide: MSAL_CONFIG,useFactory: MSALConfigFactory,},
{provide: MSAL_CONFIG_ANGULAR,useFactory: MSALAngularConfigFactory,}
])
  .bootstrapModule(AppModule)
  .catch(err => console.error(err));
}

Буя! Мы готовы. Мы ждем обещание вернуться, а затем загружаем наше приложение. В этом примере я загрузил только пару свойств из файла конфигурации, однако вы можете загрузить весь json, если хотите.

В какой-то момент в теме упоминается это решение, но его очень легко не заметить, если ваше решение построено на использовании APPINITIALIZER. Я обнаружил, что эти решения не работают для меня, библиотека MSAL пыталась загрузиться до того, как моя конфигурация возвращается с сервера.

Первый ответ на решение использует синхронный вызов с использованием XMLHttpRequest. Если вы попытаетесь использовать это решение, в журнале консоли браузера вы увидите предупреждения о том, что эти синхронные вызовы устарели.

В дополнение к этому вы можете не увидеть проблем на своем локальном компьютере, НО, если у пользователя когда-либо будет медленное подключение к Интернету, это приведет к тому, что ваше приложение перейдет в неисправимое состояние приложения из-за ошибок MSAL js.