angular-oauth2-oidc, как определить, вошел ли я где-то еще?
Я использую библиотеку angular-oauth2-oidc в сочетании с Implicit Flow с keycloak.
Там нет проблем, чтобы войти с this.oauthService.initImplicitFlow();
или выйдите с this.oauthService.logOut();
Тем не менее, мне интересно, можно ли проверить, если я уже вошел в систему в другом месте? (другой домен, но используется один и тот же сервер ключей)
Я искал документы angular-oauth2-oidc, но не нашел ни одного.
я пробовал this.oauthService.initImplicitFlowInternal();
но, похоже, работает так же, как this.oauthService.initImplicitFlow();
ОБНОВИТЬ:
У меня есть токен, использующий silentRefresh, однако он, похоже, создал еще один навигационный компонент (или, может быть, совершенно новую страницу). Проблема в том, что эта "новая" страница скрыта, и я вижу только "старую" страницу.
Я создал идентификатор для компонента nav с использованием метки времени, как вы можете видеть, на самом деле есть два идентификатора.
"Новый" компонент получил токен, поэтому он вошел в систему (но компонент скрыт!).
"Старый" компонент не знает токен, поэтому он все еще показывает "LOGIN" на панели навигации, если только я вручную не нажму кнопку и не извлеку токен из хранилища сессии по щелчку.
ОБНОВЛЕНИЕ: второй компонент - iframe. Я буду исследовать больше.
2 ответа
Как я уже упоминал в своем вопросе, нет проблем с получением относительного статуса, независимо от того, вошли вы в систему или нет. Проблема в том, что iframe, потому что только этот iframe знает, что происходит (потому что это перенаправленный URL!). Позволить моему основному приложению реагировать. Я сделал несколько настроек и "хаков".
Вот как я получил это работает. Он обнаружит, если я вошел в систему где-то еще и войдите в систему автоматически. Он также выйдет из моего приложения, если я выйду с другого сайта.
* Определить, если я вошел в систему в другом месте *
Я создал метод checkLoginState, и он отвечает за проверку, есть ли токен в моем сеансе или проверка с сервером, я уже вошел в систему.
Интервал существует только для того, чтобы периодически проверять, получил ли iframe токен.
checkLoginState() {
const claims = this.oauthService.getIdentityClaims();
if (!claims) {
if (this.ssoInterval) {
// if we are waiting on response, return;
return;
}
// try to get a token if already logged in somewhere else
this.oauthService
.loadDiscoveryDocument()
.then(() => this.oauthService.tryLogin())
.then(() => {
if (!this.oauthService.hasValidAccessToken()) {
this.setupSSOInterval();
this.oauthService.silentRefresh().catch(err => {
// this will throws a time_out error as we don't have a
valid token to refresh
// console.error('refresh error', err);
this.clearSSOInterval();
});
}
})
.catch(e => {
// console.log(e);
// if not logged in anywhere, it will throw a token error.
this.clearSSOInterval();
});
return;
}
if (this.oauthService.getIdTokenExpiration() < new Date().getTime()) {
this.userService.removeToken();
return this.logout();
}
this.isLoggedIn = true;
this.userService.authenticateWithNID(claims['email']);
}
private setupSSOInterval() {
this.ssoInterval = setInterval(() => {
if (this.isLoggedIn) {
clearInterval(this.ssoInterval);
} else {
this.checkLoginState();
}
}, 1000);
}
private clearSSOInterval() {
if (this.ssoInterval) {
clearInterval(this.ssoInterval);
}
}
и вызвать этот метод в ngOnInit ();
* Определить, если я вышел из системы в другом месте *
Чтобы определить, вышел ли я из системы, сначала установите sessionChecksEnabled
к истине (как сказал @Jeroen). Затем прослушайте изменение памяти сеанса. (потому что iframe обновит хранилище сессии)
ngOnInit() {
window.addEventListener(
'storage',
this.storageEventListener.bind(this)
);
// this is for handle the normal redirect when we login from this app
this.oauthService.events.subscribe(({ type }: OAuthEvent) => {
switch (type) {
case 'token_received': {
this.checkLoginState();
}
}
});
this.checkLoginState();
}
private storageEventListener(event: StorageEvent) {
// if there is a session change and claims is missing, means I am no longer logged in
if (event.storageArea === sessionStorage) {
if (!sessionStorage.getItem('id_token_claims_obj')) {
this.isLoggedIn = false;
}
}
}
ПОМНИТЕ, чтобы удалить this.oauthService.loadDiscoveryDocumentAndTryLogin();
в вашем методе конструктора. Это приведет к ошибкам, если вы выйдете из системы на других сайтах. (вы можете поймать ошибку, если хотите, но тот же метод был вызван внутри checkloginState()
).
Я только что понял, что мог бы также использовать слушателя хранения сеанса для проверки входа в систему (заменить интервал). Но я оставлю это сейчас.
Я предлагаю настроить тихие обновления, если вы еще этого не сделали, а затем используйте this.oauthService.silentRefresh()
,
Технически, это не отвечает на ваш вопрос прямо, потому что он не "проверяет", вошли ли вы в систему, но вместо этого просто прямо регистрирует вас в приложении. И если он потерпит неудачу (вы еще не вошли в систему), он отклонит обещание, полученное от silentRefresh()
,
Для справки, вы можете проверить мой репозиторий с этим потоком входа в систему, который поддерживает автоматическую регистрацию пользователя, даже если вход произошел в другом месте. Это мимолетный песок:
// 0. LOAD CONFIG:
// First we have to check to see how the IdServer is
// currently configured:
this.authService.loadDiscoveryDocument()
// 1. HASH LOGIN:
// Try to log in via hash fragment after redirect back
// from IdServer from initImplicitFlow:
.then(() => this.authService.tryLogin())
.then(() => {
if (!this.authService.hasValidAccessToken()) {
// 2. SILENT LOGIN:
// Try to log in via silent refresh because the IdServer
// might have a cookie to remember the user, so we can
// prevent doing a redirect:
this.authService.silentRefresh()
.catch(result => {
// Subset of situations from https://openid.net/specs/openid-connect-core-1_0.html#AuthError
// Only the ones where it's reasonably sure that sending the
// user to the IdServer will help.
const errorResponsesRequiringUserInteraction = [
'interaction_required',
'login_required',
'account_selection_required',
'consent_required',
];
if (result && result.reason && errorResponsesRequiringUserInteraction.indexOf(result.reason.error) >= 0) {
// 3. ASK FOR LOGIN:
// At this point we know for sure that we have to ask the
// user to log in, so we redirect them to the IdServer to
// enter credentials:
this.authService.initImplicitFlow();
}
});
}
});
Прямой ответ на ваш вопрос, однако, скорее всего, что вы не можете получить push-уведомление ("проверка"), когда вы вошли в систему в другом месте, потому что для этого вам нужно знать, кто вы (войти), чтобы установить проверки сеанса. (The sessionChecksEnabled
Конфигурация, однако , помогает вам "проверить", когда вы выйдете из системы в другом месте, см. этот недавний вопрос)