【问题标题】:Unable to initialize keycloak in angular with Promise with dynamic conf无法使用带有动态配置的 Promise 以角度初始化 keycloak
【发布时间】:2022-01-06 07:58:48
【问题描述】:

我想在从 keycloak-angular 库初始化 keycloak 前端组件之前调用 web 服务,以使 keycloakconf 动态化。 backendService.keycloakConfig() webservice 返回正确的值,但 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);
            }
          })
    });
  };
}

【问题讨论】:

  • 您找到答案了吗?我正在尝试做一些非常相似的事情。我最接近的是将配置存储在未经身份验证的页面上的会话存储中,然后在我进行初始化时将其拉入。然而,这不仅不是我真正想要的,而且还会导致登录时出现奇怪的无限循环(页面不断重定向到 keycloak 并返回到自身认为它未经授权) - 但实际的配置加载和初始化在技术上确实有效.

标签: angular keycloak keycloak-angular


【解决方案1】:

我不擅长 Angular,所以可能有更好的方法来做你想做的事,我很想听听,因为我想做同样的事情。

我决定在未经身份验证的页面(登录/启动页面预登录)上获取配置数据并将其保存在会话存储中:

  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 上工作。

附:如果您在没有 SSL 的情况下运行(在我的情况下是本地环境),则 checkLoginIframe 选项是必需的。否则,某些 Keycloak cookie 将无法设置正确的 SameSite 策略。

【讨论】:

  • 在@DrTeeth 下方查看我的答案。
【解决方案2】:

我在这里回答我自己的问题:

我使用这个库来指定提供者顺序:“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);
      })
    })
  }

【讨论】:

    猜你喜欢
    • 2021-10-26
    • 2015-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-06
    • 2018-05-04
    • 2019-04-14
    • 1970-01-01
    相关资源
    最近更新 更多