Угловой клиент 8 OIDC — максимальный стек вызовов превышен при авторизации

#angular #observable #openid-connect

Вопрос:

Мы используем этот клиент oidc для нашего углового интерфейса.

Приложение должно находиться в iframe другого приложения (не в angular) — обычно пользователь уже вошел в систему sts, поэтому мы хотим попытаться немедленно авторизоваться, чтобы узнать, нужно ли нам выполнить «правильную» авторизацию или нет.

Однако происходит что-то странное.

Мы используем обычную инициализацию клиентов в модуле приложения:

 export class AppModule {
  constructor(private oidcSecurityService: OidcSecurityService, private oidcConfigService: OidcConfigService) {
    this.oidcConfigService.onConfigurationLoaded.subscribe((configResult: ConfigResult) => {
    // Use the configResult to set the configurations

    const config: OpenIdConfiguration = {
      stsServer: configResult.customConfig.stsServer,
      redirect_url: configResult.customConfig.redirect_url,
      client_id: configResult.customConfig.client_id,
      response_type: 'code',
      scope: "openid profile",
      silent_renew: true,
      silent_renew_url: 'https://localhost:4200/silent-renew.html',
      log_console_debug_active: true,
    };

    this.oidcSecurityService.setupModule(config, configResult.authWellknownEndpoints);
});

 }
}
 

Затем в компоненте приложения мы сразу же пытаемся авторизоваться следующим образом:

 import { Component } from '@angular/core';
import { OidcSecurityService } from 'angular-auth-oidc-client';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  constructor(public oidcSecurityService: OidcSecurityService) { 
    if (this.oidcSecurityService.moduleSetup) {
      this.doCallbackLogicIfRequired();
  } else {
      this.oidcSecurityService.onModuleSetup.subscribe(() => {
          this.doCallbackLogicIfRequired();
      });
  }
}

ngOnInit() {
  this.oidcSecurityService.getIsModuleSetup().subscribe(() => {
    this.oidcSecurityService.getIsAuthorized().subscribe(auth => {
      if (auth === false) {
        this.oidcSecurityService.authorize();
      }
    })
  })
}

ngOnDestroy(): void {}

login() {
  this.oidcSecurityService.authorize();
}

logout() {
  this.oidcSecurityService.logoff();
}

private doCallbackLogicIfRequired() {
  this.oidcSecurityService.authorizedCallbackWithCode(window.location.toString());
}
}
 

Это приводит к запуску авторизации, возвращению к приложению, которое пытается снова авторизоваться до того, как функция oidcSecurityService.getIsAuthorized() выдаст любое значение, что приведет к бесконечному циклу, в результате которого будет превышен максимальный стек вызовов.

Однако если мы просто введем длительную задержку в компоненте приложения, он начнет вести себя так, как вы ожидали:

 ngOnInit() {
  this.oidcSecurityService.getIsModuleSetup().subscribe(() => {
    this.oidcSecurityService.getIsAuthorized().subscribe(auth => {
      if (auth === false) {
         setTimeout(() => {
           this.oidcSecurityService.authorize();
         }, 10000);
      }
    })
  })
}
 

Конечно, мы увидели бы то же поведение, что и раньше, только с десятисекундной задержкой, но мы этого не делаем. Почему? Почему тайм-аут решает проблему? Мы идем по этому неправильному пути?

Ответ №1:

Конвейер с distinctUntilChanged решил проблему, хотя при этом я вижу, что в консоли, которая была авторизована из журнала отладки библиотеки, похоже, выдает две ошибки подряд — я думаю, в этом и заключалась суть, не знаю, является ли это предполагаемым поведением.

 this.oidcSecurityService.getIsAuthorized().pipe(distinctUntilChanged()).subscribe(auth => {
      if (auth === false) {
           this.oidcSecurityService.authorize();
      }
    });