首页 > 解决方案 > 使用 Identity Server 4、VueJS 和 oidc-client 检查会话失败后自动注销

问题描述

我正在我的机器上测试服务器和客户端,我遇到以下情况:我很好地登录到客户端,做一些工作,关闭浏览器而不注销。然后我再次打开客户端,我仍然登录(预期)但一分钟后我自动注销(不预期)。

我正在使用这样配置的 oidc-client.js:

var mgr = new Oidc.UserManager({
    userStore: new Oidc.WebStorageStateStore({ store: window.localStorage }),
    authority: 'http://localhost:5000',
    client_id: 'TST_PORTAL',
    redirect_uri: window.location.origin + '/static/callback.html',
    response_type: 'code id_token token',
    scope: 'api47 openid profile read write offline_access active_dir email',
    post_logout_redirect_uri: window.location.origin + '/',
    silent_redirect_uri: window.location.origin + '/static/silent-renew.html',
    accessTokenExpiringNotificationTime: 10,
    automaticSilentRenew: true,
    filterProtocolClaims: true,
    loadUserInfo: true
})

经过进一步调查,我看到客户端正在调用 /connect/checksession(返回状态 200)以支持单点注销,然后调用 /connect/authorize?client_id... 失败(302 重定向到 /home/error)。身份服务器日志显示“授权请求中没有用户”和“客户端的无效授权类型:隐式。我配置了混合和 client_credentials。我在这里阅读了一些内容,所以我将此代码添加到我的 IdentityServer 启动中:

services.ConfigureApplicationCookie(options =>
{
   options.Cookie.SameSite = SameSiteMode.None;
});

但这似乎没有帮助。

大声思考,这可能是一个跨域问题,因为它们在不同的端口上运行,或者我没有正确设置 COR?我没有看到 cors 错误。checksession GET请求也应该有参数吗?我一直在阅读规范,它讨论的是 iframe,而不是网络流量,所以我不确定这个流量应该是什么样子。

更新:

我的应用程序的第一页是一个匿名身份验证登录页面,用于检查他们是否已登录。如果是,它将他们重定向到主页。检查的代码是这样的:

// Get signed in status without prompting to log in
getIsSignedIn() {
    console.log('Checking if signed in');
    return new Promise((resolve, reject) => {
        mgr.getUser().then(function (user) {
            if (user == null) {
                console.log('Not Signed In');
                return resolve(false)
            } else {
                if (user.expired) {
                   console.log('User expired');
                   return resolve(false)
                } else {
                    console.log('Signed In');
                    return resolve(true)
                }
            }
        }).catch(function (err) {
            console.log('Error when checking if signed in');
            return reject(false)
        });
    })
}

即使我打开一个新的浏览器,这似乎也恢复了。我什至将 Oidc.WebStorageStateStore 更改为使用默认值而不是 localStorage。

标签: identityserver4oidc-client-js

解决方案


有很多事情可能会导致这种行为。

1)单点注销(monitorSession:true)这是做什么的?-- 登录到您的应用程序后(从 IDP 服务器发布重定向后,OIDC-Client JS 将在 iframe 中包含 CheckSession 端点,并且 OIDC 库每 2 秒(默认)在内部 ping 此 iframe 以验证 idsrv.session cookie 值是否匹配使用应用程序 id 令牌中的值,如果它们不匹配,OIDC 将引发用户退出事件addUserSignedOut。这取决于您的应用程序,当这甚至从 OIDC 引发时,您希望如何处理。仅仅因为您启用了单点注销,除非应用程序处理,否则不会将用户带回登录页面。

2) Silent-Renew (automaticSilentRenew: true) 当您将此标志启用为 true 时,您无法控制何时应该进行静默更新,默认情况下,它发生在访问令牌过期时间的 1 分钟之前。所以如果silentrenew 失败,会引发silentrenew 事件addSilentRenewError。这取决于您的应用程序,当这甚至从 OIDC 提出时,您希望如何处理。

3)如果您关闭整个浏览器并转到 url 应用程序 URL,则应删除身份服务器 cookie,因为它们是会话 cookie。因此,如果您处理了单点注销事件,那么 OIDC 将在应用程序加载后的 2 秒内引发注销事件。由于您没有看到登录页面,我假设您可能没有在应用程序中处理此事件。

4)当静默更新发生时(在令牌到期时间 1 分钟之前),这一次您的应用程序将与 IDP 服务器通信,但是当您关闭浏览器时您将没有会话 cookie,您将收到静默更新错误(可能这次,您可能已经看到了您描述的错误)并且在这种情况下您必须处理silentrenew 错误,这就是您看到登录屏幕的原因。(只是基于您的输入的疯狂假设)。

希望这可以帮助 !!


推荐阅读