如何在匿名可访问页面检测IdentityServer用户的登录状态
实现ASP.NET MVC5匿名页面检测IdentityServer4用户登录状态的方案
我来帮你搞定这个需求!在ASP.NET MVC5的匿名欢迎页检测IdentityServer4的用户登录状态,核心是利用IS4提供的会话检测机制,结合前端交互来实现(毕竟匿名页面后端拿不到用户认证信息),下面是具体的步骤和代码示例:
第一步:确认MVC5应用的OIDC配置正确性
首先要确保你的ASP.NET MVC5应用已经正确配置了OpenID Connect中间件(基于Owin),关键配置要和IdentityServer4上的客户端设置匹配:
// 一般在 Startup.Auth.cs 或者 Startup.cs 中配置 app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions { ClientId = "你的MVC5客户端ID", Authority = "https://你的IdentityServer4地址", RedirectUri = "https://你的MVC5应用地址/signin-oidc", PostLogoutRedirectUri = "https://你的MVC5应用地址/signout-callback-oidc", ResponseType = "id_token", // 隐式流的响应类型,根据你的实际配置调整 Scope = "openid profile", UseTokenLifetime = true, SaveTokens = true, SignInAsAuthenticationType = DefaultAuthenticationTypes.ApplicationCookie });
同时,记得在IdentityServer4的客户端配置里,把你的MVC5应用URL加入到AllowedCorsOrigins列表中,否则后续跨域请求会被拦截。
第二步:前端实现登录状态检测
因为是匿名页面,后端无法直接获取用户的认证上下文,所以需要通过前端和IS4的端点交互来检测登录状态,这里提供两种常用方法:
方法一:调用IS4的check_session端点
IS4内置的check_session端点可以直接返回用户的会话状态,我们通过带Cookie的AJAX请求来调用它:
// 匿名欢迎页的JavaScript代码 async function checkIsUserLoggedIn() { const checkSessionEndpoint = "https://你的IdentityServer4地址/connect/checksession"; const clientId = "你的MVC5客户端ID"; const currentOrigin = window.location.origin; // 构造请求参数 const requestParams = new URLSearchParams({ client_id: clientId, origin: currentOrigin }); try { const response = await fetch(`${checkSessionEndpoint}?${requestParams}`, { credentials: "include", // 必须带上IS4的会话Cookie,才能识别用户 mode: "cors" // 允许跨域请求 }); if (response.ok) { const sessionData = await response.json(); if (sessionData.sid) { // 用户已经在IS4上登录 console.log("用户已登录,可以显示个性化内容啦!"); // 这里可以写你的业务逻辑,比如显示用户头像、跳转按钮等 } else { // 用户未登录 console.log("用户未登录,显示登录入口"); } } } catch (error) { console.error("检测登录状态出错:", error); } } // 页面加载完成后自动执行检测 window.addEventListener("load", checkIsUserLoggedIn);
方法二:嵌入静默授权iframe+postMessage通信
这种方式通过嵌入一个隐藏的iframe加载IS4的静默授权页面,然后通过postMessage来传递登录状态,稳定性更好:
<!-- 匿名欢迎页的HTML部分 --> <iframe id="silentCheckFrame" style="display: none;" src="https://你的IdentityServer4地址/connect/authorize?client_id=你的MVC5客户端ID&response_type=id_token&scope=openid&redirect_uri=https://你的MVC5应用地址/silent-check-sso&prompt=none"></iframe> <script> // 监听来自iframe的消息 window.addEventListener("message", (event) => { // 验证消息来源,防止恶意请求 if (event.origin !== "https://你的IdentityServer4地址") return; if (event.data.type === "message" && event.data.message === "ready") { // 向iframe发送检测请求 document.getElementById("silentCheckFrame").contentWindow.postMessage( { type: "check_session" }, "https://你的IdentityServer4地址" ); } else if (event.data.type === "check_session_response") { if (event.data.status === "authenticated") { console.log("用户已登录"); // 可进一步获取用户信息,比如调用userinfo端点 } else { console.log("用户未登录"); } } }); </script>
需要注意的是,你需要在MVC5应用中创建一个silent-check-sso的空回调页面(比如SilentCheckSso.cshtml),用于接收静默授权的结果,页面里只需要简单的JS来把结果通过postMessage发回主页面:
@{ Layout = null; } <script> window.addEventListener("load", () => { const urlParams = new URLSearchParams(window.location.hash.substring(1)); const idToken = urlParams.get("id_token"); if (idToken) { window.parent.postMessage({ type: "check_session_response", status: "authenticated" }, window.location.origin); } else { window.parent.postMessage({ type: "check_session_response", status: "unauthenticated" }, window.location.origin); } }); </script>
第三步:可选扩展——获取用户信息
如果检测到用户已登录,你还可以通过IS4的userinfo端点获取用户的详细信息,前提是通过静默授权拿到了id_token,示例代码如下:
async function fetchUserInfo(idToken) { const userInfoEndpoint = "https://你的IdentityServer4地址/connect/userinfo"; const response = await fetch(userInfoEndpoint, { headers: { "Authorization": `Bearer ${idToken}` } }); const userInfo = await response.json(); console.log("用户详细信息:", userInfo); // 可以把用户信息渲染到页面上 }
内容的提问来源于stack exchange,提问作者Dejan Janjušević
相关产品推荐
相关产品推荐

