#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();
}
});