首页 文章

angular-oauth2-oidc,如何检测我是否在其他地方登录?

提问于
浏览
0

我正在使用angular-oauth2-oidc库与带有keycloak的Implicit Flow .

使用 this.oauthService.initImplicitFlow(); 登录或使用 this.oauthService.logOut(); 注销没有问题

但是,我想知道,是否有可能检查我是否已经在其他地方登录了? (不同的域但使用相同的keycloak服务器)

我搜索了angular-oauth2-oidc的文档,但没有找到任何文档 .

我试过了 this.oauthService.initImplicitFlowInternal(); ,但它似乎和 this.oauthService.initImplicitFlow(); 一样

更新:

我've got the token using silentRefresh, however, it seems created another nav component (or maybe an entirely new page). The problem is, this '新' page is hidden and I can only see the '旧'页面 .
enter image description here

我使用时间戳为nav组件创建了一个id,如你所见,实际上有两个id .

'new'组件获得了令牌,因此它已登录(但组件被隐藏了!) .

“旧”组件不知道令牌,因此它仍会在导航栏上显示“LOGIN”,除非我手动创建一个按钮并在点击时从会话存储中获取令牌 .

更新:第二个组件是iframe . 我会探索更多 .

2 回答

  • 0

    我建议如果你还没有设置silent refreshes,那么使用 this.oauthService.silentRefresh() .

    从技术上讲,如果您尚未登录,那么它将拒绝从 silentRefresh() 返回的承诺.'t answer your question straight up, because it doesn' t "check" .

    作为参考,您可以检查具有此登录流的my sample repo,即使登录发生在其他地方,也支持以静默方式登录用户 . 这是实质性的:

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

    你问的直接回答可能是你在其他地方登录时无法获得推送通知("check"),因为要做到这一点你需要知道你是谁(登录)来 Build 会话检查 . (但是 sessionChecksEnabled 配置确实可以帮助你"check"当你在其他地方注销时,请参阅this recent question

  • 0

    正如我在我的问题中提到的,获取是否登录的相对状态没有问题 . 问题是iframe,因为只有iframe知道发生了什么(因为它是重定向的url!) . 让我的主应用程序响应 . 我做了一些调整和'黑客' .

    以下是我如何使用它 . 它会检测我是否在其他地方登录并自动登录 . 如果我在其他网站注销,它也会在我的应用程序中登出 .

    *** Detect if I logged in at somewhere else ***
    我创建了一个方法'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()中调用此方法;

    *** Detect if I logged out at somewhere else ***
    要检测我是否已注销,请先将 sessionChecksEnabled 设置为true(如@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() 内调用了相同的方法) .

    我刚刚意识到我也可以使用会话存储监听器进行登录检查(替换间隔) . 但我现在就把它留下来 .

相关问题