无法使用带有动态配置的 Promise 在 angular 中初始化 keycloak
Unable to initialize keycloak in angular with Promise with dynamic conf
我想在从 keycloak-angular 库强制初始化 keycloak 前端组件之前调用一个 web 服务,以使 keycloakconf 动态化。 backendService.keycloakConfig() 网络服务返回正确的值,但 isInitialized 变量始终为 false。
我认为混合使用 Promise 和 Observable 会扰乱初始化。
这是代码:
import {KeycloakService} from 'keycloak-angular';
import {BackendService} from "./service/backend.service";
export function initializer(keycloak: KeycloakService, backendService: BackendService): () => Promise<any> {
return (): Promise<any> => {
return new Promise<void>(async (resolve, reject) => {
backendService.keycloakConfig()
.toPromise()
.then(
keycloakConfig => {
try {
keycloak.init({
config: keycloakConfig,
enableBearerInterceptor: true,
loadUserProfileAtStartUp: false,
initOptions: {
checkLoginIframe: false
},
bearerExcludedUrls: ['/assets']
}).then((isInitialize) => {
console.log("Initialized keycloak", isInitialize)
}).catch(reason => {console.log(reason)})
resolve();
} catch (error) {
console.log("error", error)
reject(error);
}
})
});
};
}
我对 Angular 不是很好,所以可能有更好的方法来做你想做的事,我很想听听,因为我也想做同样的事情。
我在未授权页面(landing/splash 登录前页面)上确定的是获取配置数据并将其粘贴到会话存储中:
set keycloakConfig(val: string) {
sessionStorage.setItem('kcc', val);
}
fetchKeycloakConfig() {
console.log("Fetching keycloak config from service.");
this._restapiService.getKeycloakConfig().then((data) => {
this.keycloakConfig = JSON.stringify(data);
});
}
然后在应用程序初始化时,我继续从不需要任何类型的会话存储中提取 promise/async/await/etc:
function initializeKeycloak(keycloak: KeycloakService) {
return () => {
let storedConfig: string = sessionStorage.getItem('kcc');
if (storedConfig != null) {
console.log("Initializing Keycloak client with config: " + storedConfig);
let keycloakConfig = JSON.parse(storedConfig);
return keycloak.init({
config: {
url: keycloakConfig.url,
realm: keycloakConfig.realm,
clientId: keycloakConfig.resource
},
initOptions: {
onLoad: 'check-sso',
silentCheckSsoRedirectUri:
window.location.origin + '/assets/silent-check-sso.html',
checkLoginIframe: false
},
});
}
else {
console.log("Keycloak config not stored. No client available.");
return null;
}
}
}
...
@NgModule({
...
providers: [
CookieService,
KeycloakService,
{
provide: APP_INITIALIZER,
useFactory: initializeKeycloak,
multi: true,
deps: [KeycloakService],
}
],
...
})
就像我说的,我不喜欢这个。我更愿意按需从 api 中提取,但我还没有弄清楚如何让所有异步调用在 init 上工作。
P.S。如果您 运行 没有 SSL(在我的例子中是本地环境),则 checkLoginIframe
选项是必需的。否则某些 Keycloak cookie 将不会设置正确的 SameSite 策略。
我在这里回答我自己的问题:
我使用这个库来指定提供程序顺序:“ngx-ordered-initializer”:“1.0.0”
在 app.module.ts 中:
providers: [
KeycloakService,
{provide: ORDERED_APP_INITIALIZER, useFactory: initializerConfig, deps: [CommonService], multi: true},
{provide: ORDERED_APP_INITIALIZER, useFactory: initializer, deps: [KeycloakService, CommonService], multi: true},
ORDERED_APP_PROVIDER
},
]
export function initializer(keycloak: KeycloakService, commonService: CommonService): () => Promise<any> {
return (): Promise<any> => {
return new Promise<void>(async (resolve, reject) => {
try {
await keycloak.init({
config: commonService.customKeyCloakConfig,
loadUserProfileAtStartUp: false,
initOptions: {
checkLoginIframe: false
},
enableBearerInterceptor: true,
bearerExcludedUrls: ['']
}).then((isInitialize) => {
console.log("keycloak is initialized : ", isInitialize)
})
resolve();
} catch (error) {
console.log("error happened during Keycloak initialization : ", error)
reject(error);
}
});
};
}
公务员:
customKeyCloakConfig: any;
constructor(private apiService: ApiService, private config: ConfigService) {
}
public keycloakConfig(){
return new Promise((resolve, reject) => {
this.apiService.get<any>(this.config.KEYCLOAK_CONFIG_CUSTOM).subscribe(res => {
this.customKeyCloakConfig = res;
resolve(true);
})
})
}
我想在从 keycloak-angular 库强制初始化 keycloak 前端组件之前调用一个 web 服务,以使 keycloakconf 动态化。 backendService.keycloakConfig() 网络服务返回正确的值,但 isInitialized 变量始终为 false。
我认为混合使用 Promise 和 Observable 会扰乱初始化。
这是代码:
import {KeycloakService} from 'keycloak-angular';
import {BackendService} from "./service/backend.service";
export function initializer(keycloak: KeycloakService, backendService: BackendService): () => Promise<any> {
return (): Promise<any> => {
return new Promise<void>(async (resolve, reject) => {
backendService.keycloakConfig()
.toPromise()
.then(
keycloakConfig => {
try {
keycloak.init({
config: keycloakConfig,
enableBearerInterceptor: true,
loadUserProfileAtStartUp: false,
initOptions: {
checkLoginIframe: false
},
bearerExcludedUrls: ['/assets']
}).then((isInitialize) => {
console.log("Initialized keycloak", isInitialize)
}).catch(reason => {console.log(reason)})
resolve();
} catch (error) {
console.log("error", error)
reject(error);
}
})
});
};
}
我对 Angular 不是很好,所以可能有更好的方法来做你想做的事,我很想听听,因为我也想做同样的事情。
我在未授权页面(landing/splash 登录前页面)上确定的是获取配置数据并将其粘贴到会话存储中:
set keycloakConfig(val: string) {
sessionStorage.setItem('kcc', val);
}
fetchKeycloakConfig() {
console.log("Fetching keycloak config from service.");
this._restapiService.getKeycloakConfig().then((data) => {
this.keycloakConfig = JSON.stringify(data);
});
}
然后在应用程序初始化时,我继续从不需要任何类型的会话存储中提取 promise/async/await/etc:
function initializeKeycloak(keycloak: KeycloakService) {
return () => {
let storedConfig: string = sessionStorage.getItem('kcc');
if (storedConfig != null) {
console.log("Initializing Keycloak client with config: " + storedConfig);
let keycloakConfig = JSON.parse(storedConfig);
return keycloak.init({
config: {
url: keycloakConfig.url,
realm: keycloakConfig.realm,
clientId: keycloakConfig.resource
},
initOptions: {
onLoad: 'check-sso',
silentCheckSsoRedirectUri:
window.location.origin + '/assets/silent-check-sso.html',
checkLoginIframe: false
},
});
}
else {
console.log("Keycloak config not stored. No client available.");
return null;
}
}
}
...
@NgModule({
...
providers: [
CookieService,
KeycloakService,
{
provide: APP_INITIALIZER,
useFactory: initializeKeycloak,
multi: true,
deps: [KeycloakService],
}
],
...
})
就像我说的,我不喜欢这个。我更愿意按需从 api 中提取,但我还没有弄清楚如何让所有异步调用在 init 上工作。
P.S。如果您 运行 没有 SSL(在我的例子中是本地环境),则 checkLoginIframe
选项是必需的。否则某些 Keycloak cookie 将不会设置正确的 SameSite 策略。
我在这里回答我自己的问题:
我使用这个库来指定提供程序顺序:“ngx-ordered-initializer”:“1.0.0”
在 app.module.ts 中:
providers: [
KeycloakService,
{provide: ORDERED_APP_INITIALIZER, useFactory: initializerConfig, deps: [CommonService], multi: true},
{provide: ORDERED_APP_INITIALIZER, useFactory: initializer, deps: [KeycloakService, CommonService], multi: true},
ORDERED_APP_PROVIDER
},
]
export function initializer(keycloak: KeycloakService, commonService: CommonService): () => Promise<any> {
return (): Promise<any> => {
return new Promise<void>(async (resolve, reject) => {
try {
await keycloak.init({
config: commonService.customKeyCloakConfig,
loadUserProfileAtStartUp: false,
initOptions: {
checkLoginIframe: false
},
enableBearerInterceptor: true,
bearerExcludedUrls: ['']
}).then((isInitialize) => {
console.log("keycloak is initialized : ", isInitialize)
})
resolve();
} catch (error) {
console.log("error happened during Keycloak initialization : ", error)
reject(error);
}
});
};
}
公务员:
customKeyCloakConfig: any;
constructor(private apiService: ApiService, private config: ConfigService) {
}
public keycloakConfig(){
return new Promise((resolve, reject) => {
this.apiService.get<any>(this.config.KEYCLOAK_CONFIG_CUSTOM).subscribe(res => {
this.customKeyCloakConfig = res;
resolve(true);
})
})
}