"Невозможно прочитать свойство 'displayCall' из неопределенного при новом AuthenticationContex ..." - PullRequest
0 голосов
/ 06 февраля 2020

Как дела?

Итак, я только начал работать с новейшей версией Angular, используя TypeScript, и у меня возникла проблема при попытке загрузить файл конфигурации в мое приложение.

Вещи go примерно так: я работаю над проектом, который использует MsAdalAngular6Module для Azure аутентификации. Когда я получил проект, все параметры конфигурации были жестко запрограммированы, поэтому я следовал инструкциям: https://devblogs.microsoft.com/premier-developer/angular-how-to-microsoft-adal-for-angular-6-with-configurable-settings/, чтобы использовать пакет в более реалистичном c сценарии. Но затем, как вы увидите в первой ссылке, мне пришлось создать сервис для динамической загрузки моих файлов конфигурации, следуя этим инструкциям: https://devblogs.microsoft.com/premier-developer/angular-how-to-editable-config-files/

После этого дела пошли довольно хорошо, Я был в состоянии загрузить мои файлы конфигурации, без проблем. Но проблема началась, когда мне нужно было создать HttpInterceptor , чтобы вставить токен аутентификации в заголовок каждого запроса. В принципе, я не могу использовать оба одновременно (сервис, который загружает файл конфигурации и HttpInterceptor), иначе я получаю эту ошибку:

Ошибка при попытке загрузить файлы конфигурации

Я предполагаю, что запрос, исходящий от службы конфигурации, выполняется до загрузки MsAdalAngular6Module. Таким образом, когда запрос сделан, у него нет некоторых свойств, которые он должен иметь для того, чтобы он был аутентифицирован MsAdalAngular6Service. Конечно, это всего лишь предположение.

Вот код:

Служба конфигурации


    import { Injectable } from '@angular/core';
    import { HttpClient } from '@angular/common/http';
    import { environment } from '../environments/environment';
    import { IAppConfig } from './models/app-config.model';

    @Injectable()
    export class AppConfig {
        static settings: IAppConfig;
        constructor(private http: HttpClient) { }
        load() {
            const jsonFile = `assets/config/config.${environment.name}.json`;
            return new Promise<void>((resolve, reject) => {
                this.http.get(jsonFile, { withCredentials: true }).toPromise().then((response: IAppConfig) => {
                    AppConfig.settings = <IAppConfig>response;
                    resolve();
                }).catch((response: any) => {
                    reject(`Could not load file '${jsonFile}': ${JSON.stringify(response)}`);
                });
            });
        }
    }

Перехватчик Http


    import { Injectable } from '@angular/core';
    import { HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
    import { mergeMap } from 'rxjs/operators';
    import { MsAdalAngular6Service } from 'microsoft-adal-angular6';

    @Injectable()
    export class InsertAuthTokenInterceptor implements HttpInterceptor {

        constructor(private adal: MsAdalAngular6Service) { }

        intercept(req: HttpRequest<any>, next: HttpHandler) {
            // get api url from adal config
            const resource = this.adal.GetResourceForEndpoint(req.url);
            if (req.withCredentials){
                return next.handle(req);
            }

            if (!resource || !this.adal.isAuthenticated) {
                return next.handle(req);
            }

            // merge the bearer token into the existing headers
            return this.adal.acquireToken(resource).pipe(
                mergeMap((token: string) => {
                    const authorizedRequest = req.clone({
                        headers: req.headers.set('Authorization', `Bearer ${token}`),
                    });
                    return next.handle(authorizedRequest);
            }));
        }
    }

И то, как я использую его в app.module.ts :

    ...
    let adalConfig: any;

    export const interceptorProviders =
      [
        {provide: HTTP_INTERCEPTORS, useClass: InsertAuthTokenInterceptor, multi: true}
      ];



    export function msAdalAngular6ConfigFactory() {
      return adalConfig;
    }

    export function initializeApp(appConfig: AppConfig) {
      const promise = appConfig.load().then(() => {
        adalConfig = {
          tenant: AppConfig.settings.adalConfig.tenant,
          clientId: AppConfig.settings.adalConfig.clientId,
          endpoints: AppConfig.settings.adalConfig.endpoints,
          navigateToLoginRequestUrl: false,
          cacheLocation: AppConfig.settings.adalConfig.cacheLocation
        };
      });

      return () => promise;
    }

    ...

Часть поставщиков

    ...
      providers: [
        AppConfig,
        {
          provide: APP_INITIALIZER,
          useFactory: initializeApp,
          deps: [AppConfig],
          multi: true,
        },
        interceptorProviders,
        AuthenticationGuard,
        LoaderService,
        MsAdalAngular6Service,
        {
          provide: 'adalConfig',
          useFactory: msAdalAngular6ConfigFactory,
          deps: []
        },
        AuthenticationGuard
      ]
    ...

1 Ответ

0 голосов
/ 06 февраля 2020

Хорошо, думаю, я нашел решение. Я просто не знаю, насколько это надежно. Я использовал локальный клиент htpp. Затем сервис AppConfig стал примерно таким:

    import { Injectable } from '@angular/core';
    import { HttpBackend, HttpClient } from '@angular/common/http';
    import { environment } from '../environments/environment';
    import { IAppConfig } from './models/app-config.model';

    const URL = `assets/config/config.${environment.name}.json`;

    @Injectable({ providedIn: 'root' }) export class AppConfig {
        static settings: IAppConfig;

        private httpClient: HttpClient; constructor(httpBackend: HttpBackend) {
            // Use local HttpClient to avoid interceptor loop
            this.httpClient = new HttpClient(httpBackend);
        }

        getAppConfig() {
            return new Promise<void>((resolve, reject) => {
                this.httpClient.get(URL, { withCredentials: true }).toPromise().then((response: IAppConfig) => {
                    AppConfig.settings = <IAppConfig>response;
                    resolve();
                }).catch((response: any) => {
                    reject(`Could not load file '${URL}': ${JSON.stringify(response)}`);
                });
            });
        }
    }


...