0

OAuth 2.0 を使用して、Angular アプリケーションでユーザーのトークンを取得しています。angular-oauth2-oidcOAuth フローの処理には一般的な lib を使用します。そのため、AppComponent で oAuthService をセットアップしangular-oauth2-oidc、ログイン コンポーネントで を呼び出して oAuth フローを開始しinitCodeFlow()ます。ユーザーはリダイレクトされて資格情報を入力し、その後リダイレクトされて、AppComponent でトークンを受け取り、それを次のトークンとして DataService TokenSubject に入れます。

しかし今、MainPageComponent のヘッダーでそのトークンを使用して API 呼び出しを行いたいと考えています。したがって、MainPage で TokenSubject をサブスクライブし、トークンを受け取ると、サブスクライブ ブロックのコードが実行されます。

しかし、メイン ページが構築されるよりも早くトークンが送信されてきた場合はどうなるでしょうか。次に、次の Token 値が AppComponent によって発行されたときに、メイン ページの TokenSubject にまだサブスクライブしていません。よくわかりませんが、メイン ページが開かないことがありました。おそらくこれが原因だと思います。

TokenSubject を発行する前に、メイン ページが TokenSubject にサブスクライブされていることを確認する最善の方法は何ですか?

私のAppComponent

import { OAuthService } from 'angular-oauth2-oidc';
...

export class AppComponent implements OnInit {
    token: Token = {
      access_token: null,
      refresh_token: null
};

constructor(private oauthService: OAuthService,
                private adapterService: AdapterService,
                private dataService: DataService,
                private logger: NGXLogger) {
}

ngOnInit() {
        this.configureOAuthService();
        this.subscribeToOAuthEvents();
    }

configureOAuthService() {
        const authConfig: AuthConfig = {
            issuer: environment.oauthLoginUrl,
            redirectUri: environment.oauthRedirectUrl,
            clientId: environment.apiKey,
            scope: 'openid',
            responseType: 'code',
            showDebugInformation: true,
            disablePKCE: false,
            oidc: true,
            disableAtHashCheck: false,
        };

        this.oauthService.configure(authConfig);
        this.oauthService.tokenValidationHandler = new JwksValidationHandler();
        this.oauthService.loadDiscoveryDocumentAndTryLogin();
}

subscribeToOAuthEvents() {
        this.oauthService.events.subscribe(e => {
            if (e.type === 'token_received' || e.type === 'token_refreshed' ) {
                this.storeTokenInDataService();

                const self = this;
                // this will wait for 2 hours minus 30 sec before it refreshes the access token;
                setTimeout(() => { self.refreshToken(self); }, 7_170_000);
            } else if (e.type === 'token_expires') {
                this.logger.log('token_expires, going to refresh');
                this.refreshToken(this);
            } else if (e instanceof OAuthErrorEvent) {
                this.logger.error('OAuth error:', e);
            } else {
                this.logger.log('OAuthEvent:', e);
            }
        });
    }

    storeTokenInDataService() {
        this.token.access_token = this.oauthService.getAccessToken();
        this.token.refresh_token = this.oauthService.getRefreshToken();
        this.dataService.nextToken(this.token);
    }

私のメインページでは、sharedToken を購読していますが、トークンが発行される前にそれが常に起こるかどうかはわかりません:

ngOnInit(): void {
  console.log('going to get the token from dataService');
  this.dataService.sharedToken
    .pipe(
      takeUntil(this.destroy$),
      tap(token => {
        this.token = token;
        console.log('got Token');
      }),
      switchMap(token => {
        this.headers = this.createHeaders(token.access_token);

        return this.adapterService.getUserInfo(this.headers);
      }))
    .subscribe(UserInfo => {
      this.logger.log('received userInfo : ', userInfo);
      ... 
  });
 }
}

私の DataService では、次のようになります。

  private token = new Subject<Token>();
  sharedPToken = this.token ;

  nextToken(token: Token) {
    this.token.next(token);
  }

更新:質問は解決されました。最終的なメイン コンポーネントは次のようになります。

ngOnInit(): void {
  this.dataService.sharedTokenReplaySubject
    .pipe(
      takeLast(1),
      tap(token => {
        this.token = token;
        console.log('got Token');
      }),
      switchMap(token => {
        this.headers = this.createHeaders(token.access_token);

        return this.adapterService.getUserInfo(this.headers);
      }))
    .subscribe(UserInfo => {
      this.logger.log('received userInfo : ', userInfo);
      ... 
  });
 }
}
4

1 に答える 1