"Cannot read property 'displayCall' of undefined at new AuthenticationContex ..."
"Cannot read property 'displayCall' of undefined at new AuthenticationContex ..."
最近怎么样?
所以,我刚开始使用 TypeScript 使用最新版本的 Angular,但在尝试将配置文件加载到我的应用程序时遇到了问题。
事情大致是这样的:我正在开发一个项目,该项目使用 MsAdalAngular6Module for Azure验证。当我得到项目时,所有配置设置都是硬编码的,所以我按照以下说明进行操作:https://devblogs.microsoft.com/premier-developer/angular-how-to-microsoft-adal-for-angular-6-with-configurable-settings/ to use the package in a more realistic scenario. But then, as you gonna find in the first link, I had to create a service to load my configuration files dynamically following those instructions: https://devblogs.microsoft.com/premier-developer/angular-how-to-editable-config-files/
之后一切顺利,我能够加载我的配置文件,没问题。但是当我需要创建一个 HttpInterceptor 以在每个请求的 header 中插入身份验证令牌时,问题就开始了。基本上,我不能同时使用两者(加载配置文件的服务和 HttpInterceptor),否则我会收到此错误:
Error when trying to load configuration files
我的猜测是:来自配置服务的请求是在 MsAdalAngular6Module 加载之前发出的。因此,当发出请求时,它没有一些属性,它应该具有 ir order 以便它被 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
]
...
好的,我想我找到了解决办法。只是不知道可信度如何。我使用了一个本地的 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)}`);
});
});
}
}
最近怎么样?
所以,我刚开始使用 TypeScript 使用最新版本的 Angular,但在尝试将配置文件加载到我的应用程序时遇到了问题。
事情大致是这样的:我正在开发一个项目,该项目使用 MsAdalAngular6Module for Azure验证。当我得到项目时,所有配置设置都是硬编码的,所以我按照以下说明进行操作:https://devblogs.microsoft.com/premier-developer/angular-how-to-microsoft-adal-for-angular-6-with-configurable-settings/ to use the package in a more realistic scenario. But then, as you gonna find in the first link, I had to create a service to load my configuration files dynamically following those instructions: https://devblogs.microsoft.com/premier-developer/angular-how-to-editable-config-files/
之后一切顺利,我能够加载我的配置文件,没问题。但是当我需要创建一个 HttpInterceptor 以在每个请求的 header 中插入身份验证令牌时,问题就开始了。基本上,我不能同时使用两者(加载配置文件的服务和 HttpInterceptor),否则我会收到此错误:
Error when trying to load configuration files
我的猜测是:来自配置服务的请求是在 MsAdalAngular6Module 加载之前发出的。因此,当发出请求时,它没有一些属性,它应该具有 ir order 以便它被 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
]
...
好的,我想我找到了解决办法。只是不知道可信度如何。我使用了一个本地的 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)}`);
});
});
}
}