使用 angular-oauth2-oidc 实现 OAuth2 代码流

sso*_*nez 5 oauth-2.0 angular angular-oauth2-oidc

我正在使用 Angular-oauth2-oidc 在 Angular 10 应用程序中实现授权代码流。主要思想很简单,我只有一个带有按钮的应用程序组件。当用户单击它时,他必须被重定向到身份验证提供程序登录页面,并在成功登录后返回到应用程序。

身份验证由以下服务处理:

export class AuthenticationService {
  private authCodeFlowConfig: AuthConfig = {
    issuer: ...
  };

  constructor(public oauthService: OAuthService) {
    this.oauthService.configure(this.authCodeFlowConfig);

    if (location.href.indexOf('?code') > 0) {
      this.oauthService.loadDiscoveryDocumentAndLogin();
    }
  }

  async login(): Promise<void> {
    await this.oauthService.loadDiscoveryDocumentAndLogin();
  }
}
Run Code Online (Sandbox Code Playgroud)

这可行,但我对构造函数中的 URL 检查有点困扰。但是,如果我不这样做,用户将被正确重定向到登录页面,并在成功登录后返回应用程序,但他会陷入代码流的中间。事实上,授权代码存在于 URL 中,但是 Angular-oauth2-oidc 没有处理它,这就是为什么如果存在“code”查询字符串,我必须再次调用构造函数中的登录方法。

我怀疑我做错了什么,因为我期望 angular-oauth2-oidc 会自动处理代码。

我在这里错过了什么吗?

Jer*_*oen 1

您可以查看我的示例如何通过登录逻辑的要点来做到这一点,如下所示:

this.oauthService.loadDiscoveryDocument()

  // 1. HASH LOGIN: Try to log in via hash fragment after redirect back from IdServer:
  .then(() => this.oauthService.tryLogin())
  .then(() => {
    if (this.oauthService.hasValidAccessToken()) {
      return Promise.resolve();
    }

    // 2. SILENT LOGIN: Try to log in via a refresh because then we can prevent needing to redirect the user:
    return this.oauthService.silentRefresh()
      .then(() => Promise.resolve())
      .catch(result => {
        // Subset of situations from https://openid.net/specs/openid-connect-core-1_0.html#AuthError
        const errorResponsesRequiringUserInteraction = ['interaction_required', 'login_required', 'account_selection_required', 'consent_required'];

        if (result && result.reason && errorResponsesRequiringUserInteraction.indexOf(result.reason.error) >= 0) {
          console.warn('User interaction is needed to log in, we will wait for the user to manually log in. Could\'ve also forced user to log in here.');
          return Promise.resolve();
        }

        return Promise.reject(result);
      });
  })

  .then(() => {
    this.isDoneLoadingSubject$.next(true);

    if (this.oauthService.state && this.oauthService.state !== 'undefined' && this.oauthService.state !== 'null') {
      let stateUrl = this.oauthService.state;
      if (stateUrl.startsWith('/') === false) {
        stateUrl = decodeURIComponent(stateUrl);
      }
      console.log(`There was state of ${this.oauthService.state}, so we are sending you to: ${stateUrl}`);
      this.router.navigateByUrl(stateUrl);
    }
  })
  .catch(() => this.isDoneLoadingSubject$.next(true));
Run Code Online (Sandbox Code Playgroud)

不需要?code自己去嗅探,图书馆(按照上面的指示)会为你处理。