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 Конфигурация, однако , помогает вам "проверить", когда вы выйдете из системы в другом месте, см. этот недавний вопрос)

Другие вопросы по тегам