我正在使用APP_INITIALIZER
来加载特定于环境的变量。我需要在authConfigFactory
中使用这些变量,但是工厂会在APP_INITIALIZER
完成应用程序配置之前保持加载状态。
我正在使用此库:https://github.com/manfredsteyer/angular-oauth2-oidc
我想在我的身份验证配置工厂中使用APP_CONFIG.authConfig.allowedUrls
的值。如何确保它在auth工厂之前先设置配置。
我在工厂遇到此错误:Cannot read property 'authConfig' of undefined
app.module.ts
:
providers: [
AppConfigService,
{
provide: APP_INITIALIZER,
useFactory: (config: AppConfigService) => () => config.load(),
multi: true,
deps: [AppConfigService]
},
{
provide: OAuthModuleConfig,
useFactory: authConfigFactory
}
]
app.config.ts
:
export let APP_CONFIG: AppConfig;
@Injectable()
export class AppConfigService {
constructor(
private injector: Injector
) {}
config = null;
public load() {
const http = this.injector.get(HttpClient);
return http
.get('../assets/config/config.json')
.pipe(
tap(returnedConfig => {
const t = new AppConfig();
APP_CONFIG = Object.assign(t, returnedConfig);
})
)
.toPromise();
}
}
auth-config-factor
:
export function authConfigFactory(): OAuthModuleConfig {
return {
resourceServer: {
allowedUrls: APP_CONFIG.authConfig.allowedUrls,
sendAccessToken: true
}
};
}
答案 0 :(得分:1)
我以前遇到过这个问题,没有运气就尝试了很多可能性,唯一的解决方案是我使用了ngrx / store
在app.config.ts中,您可以调度操作以将配置保存在商店中,然后可以通过执行以下操作在其他服务中获取它:store.select()订阅它并进行控制
app.module.ts
providers: [
AuthService, // oidc-client.ts where i need the config from json
DataService,
ConfigService,
{
provide: APP_INITIALIZER,
useFactory: loadConfig,
deps: [ConfigService],
multi: true,
},
config.service.ts
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Store } from '@ngrx/store';
import { IAppStore } from '../models/store.model';
import * as ConfigActions from '../store/actions/config.actions';
@Injectable()
export class ConfigService {
public config: any = {};
constructor(private http: HttpClient, private store: Store<IAppStore>) {}
getConfig(key: string): string {
return this.config[key] || '';
}
public loadConfig() {
return new Promise((resolve, reject) => {
this.http.get('app-config.json').subscribe(
(response) => {
this.config = response;
this.store.dispatch(new ConfigActions.AddConfig(response)); // dispatch action to update the store
resolve(true);
}
);
});
}}
AuthService
import { Log, User, UserManager, WebStorageStateStore } from 'oidc-client';
...
@Injectable()
export class AuthService {
private _userManager: UserManager;
public _user: User;
constructor(
private store: Store<IAppStore>
private httpClient: HttpClient,
private route: Router,
private configs: ConfigService
) {
this.store.select('appConfig').subscribe((configdata) => {
Log.logger = console;
const config = {
authority: configdata.stsAuthority,
client_id: configdata.clientId,
redirect_uri: `${configdata.clientRoot}/#/auth-callback#`,
scope: 'openid profile fusionApi.full_access',
response_type: 'id_token token',
post_logout_redirect_uri: `${configdata.clientRoot}?postLogout=true`, // delet all stored tokens after logout
userStore: new WebStorageStateStore({ store: window.localStorage }),
automaticSilentRenew: true,
silent_redirect_uri: `${configdata.clientRoot}/assets/html/silent-refresh-redirect.html`,
};
this._userManager = new UserManager(config);
this._userManager.getUser().then((user) => {
if (user && !user.expired) {
this._user = user;
}
});
...
}
login(): Promise<any> {
return this._userManager.signinRedirect();
}
...
答案 1 :(得分:1)
我有同样的问题。 OAuthModuleConfig需要同步设置。因此,需要在创建OAuthModuleConfig之前(在工厂中)加载设置。
我通过在引导AppModule之前加载设置来实现它。
Main.ts:
fetch('/assets/config.json')
.then(response => response.json())
.then(config => {
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic([{ provide: APP_SETTINGS, useValue: config }])
.bootstrapModule(AppModule)
.catch(err => console.error(err));
});
App.module.ts
在模块声明内:
....
providers: [
{ provide: OAuthModuleConfig, useFactory: authConfigFactory, deps: [APP_SETTINGS] },
],
bootstrap: [AppComponent]
.....
export function authConfigFactory(settings: AppSettings): OAuthModuleConfig {
return {
resourceServer: {
allowedUrls: settings.protectedUrls,
sendAccessToken: true,
}
};
}
答案 2 :(得分:0)
我有同样的问题并解决。
模块工厂:
import { InjectionToken } from '@angular/core';
import { HttpClient, HttpBackend } from '@angular/common/http';
import { map } from 'rxjs/operators';
import { AuthorizationService } from './authorization.service';
export const AUTH_CONFIG = new InjectionToken<string>('auth.config.path', {
factory: () => 'config.json',
});
export function CheckAuthorizationState(handler: HttpBackend, authService: AuthorizationService, path: string) {
return async () => {
const http = new HttpClient(handler);
// get config for authorization
await http.get(path)
.pipe(
map((response: any) => {
authService.init(response);
})
).toPromise();
// check authorization
await authService.checkAuthorization();
};
}
模块:
import { NgModule, APP_INITIALIZER, ModuleWithProviders, InjectionToken } from '@angular/core';
import { CommonModule } from '@angular/common';
import { AuthorizationService } from './authorization.service';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { AuthorizationGuardService } from './authorization-guard.service';
import { AuthorizationInterceptor } from './authorization-interpretator';
import { HttpBackend, HttpClient } from '@angular/common/http';
import { map } from 'rxjs/operators';
import { CheckAuthorizationState, AUTH_CONFIG } from './module-factories';
@NgModule({
imports: [
CommonModule
],
providers: [
AuthorizationService,
AuthorizationGuardService,
{
provide: APP_INITIALIZER,
useFactory: CheckAuthorizationState,
deps: [HttpBackend, AuthorizationService, AUTH_CONFIG],
multi: true
},
{
provide: HTTP_INTERCEPTORS,
useClass: AuthorizationInterceptor,
multi: true
}
],
declarations: []
})
export class AuthorizationModule {
static forRoot(path: string): ModuleWithProviders {
return {
ngModule: AuthorizationModule,
providers: [
{ provide: AUTH_CONFIG, useValue: path }
]
};
}
}
这是我为您发布的授权库:https://www.npmjs.com/package/sso-authorization-oidc-client
答案 3 :(得分:0)
我今天才遇到此问题,以下是我如何解决此问题的方法。希望这可能对某人有所帮助。
这在某种程度上特定于angular-oauth2-oidc
export const oauthModuleConfigFactory = (config: AppConfig): OAuthModuleConfig => ({
resourceServer: {
allowedUrls: [config.apiUrl],
sendAccessToken: true
}
});
// OAuthModuleConfig is provided by OAuthModule as useValue
// and Angular resolves useValue providers before APP_INITIALIZER
// This may be a bug, since Angular still attempts to resolve the value
// even if it has been overriden with a useFactory as below
const fixForAppInitializers = ({ ngModule, providers = [] }: ModuleWithProviders<any>) => ({
ngModule,
providers: [...providers.filter((value: any) => value.provide !== OAuthModuleConfig)]
});
@NgModule({
imports: [fixForAppInitializers(OAuthModule.forRoot())],
providers: [
AuthGuard,
{ provide: OAuthModuleConfig, useFactory: oauthModuleConfigFactory, deps: [APP_CONFIG] },
...
]
})
export class AuthModule { }
但这还不够,因为OAuthModule
的{{1}}需要DefaultOAuthInterceptor
,这需要首先加载OAuthModuleConfig
,但是为了加载配置,我们需要使用app.config.json
根据请求注入HttpClient
,从而在下面抛出HTTP_INTERCEPTORS
错误。
这是我解决该问题的方法:
config is not loaded