You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

IdentityModel实现:.NET5 MVC对接IS4如何验证刷新过期access_token

.NET 5 MVC对接IdentityServer4 access_token过期无法自动重定向认证问题

背景

我正尝试将.NET 5(MVC)开发的新客户端应用对接现有IdentityServer4(简称IS4)。IS4同时承担客户端身份认证、提供claims/角色,以及独立Web API访问后端系统所需的access_token的功能。新客户端使用IdentityModel包处理认证授权,目前认证、授权功能均正常,仅遇到access_token过期相关的问题。

IS4客户端配置参数

标注(default)的为IdentityModel/IS4默认设置:

  • IdentityTokenLifetime:300秒/5分钟 (default)
  • IdentityAccessToken:300秒/5分钟(为便于测试做了缩短)
  • AuthorizationCodeLifetime:300秒/5分钟 (default)

运行场景

场景一(正常)

  1. 用户访问网页,被重定向到IS4登录页
  2. 用户输入账号密码完成认证,被重定向回Web应用的安全区域
  3. 用户访问安全页面时,携带当前用户的access_token请求外部API拉取用户数据
  4. 请求返回用户数据,页面正常加载展示
  5. 运行完全正常

场景二(正常)

  1. 用户访问网页,被重定向到IS4登录页
  2. 用户已通过Cookie完成IS4认证,直接认证通过,被重定向回Web应用的安全区域
  3. 用户访问安全页面时,携带当前用户的access_token请求外部API拉取用户数据
  4. 请求返回用户数据,页面正常加载展示
  5. 运行完全正常

场景三(问题场景)

  1. 用户在网页停留15分钟后刷新页面
  2. 用户仍处于网站登录状态,因此没有被重定向到IS4
  3. 刷新后用户访问安全页面,携带当前用户的access_token请求外部API拉取用户数据
  4. 请求返回为空,因为access_token早在10分钟前就已过期
  5. 运行失败

场景四(正常)

  1. 场景三发生后,用户看到错误重启浏览器
  2. 用户访问网页,被重定向到IS4登录页
  3. 用户已通过Cookie完成IS4认证,直接认证通过,被重定向回Web应用的安全区域
  4. 用户访问安全页面时,携带当前用户的access_token请求外部API拉取用户数据
  5. 请求返回用户数据,页面正常加载展示(原因是本次IS4"登录"生成了新的有效期内的access_token)
  6. 运行完全正常

问题描述与期望效果

问题为场景三的异常情况。期望效果是:[Authorization]校验不会放行过期会话(过期access_token),而是基于用户仍然有效的Cookie自动重定向到IS4重新认证,与场景四逻辑一致。

已尝试的解决方案

  • 延长IdentityAccessToken有效期:没有解决根本问题,只是将问题发生的时间延后到新的expire_date
  • 在现有IS4实现中使用IdentityModel客户端"Web5"示例:复现了相同的问题

业务约束

应用要求access_token有效期较短,以便后端claims/roles变更时可以快速更新用户权限,同时需要支持"持久化"登录,减少用户输入账号信息的频率。
如果存在思路或者对相关机制的理解错误,可告知正确流程,最好附带可运行的示例。

现有客户端IdentityModel配置

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

services
    .AddAuthentication(options => {
        options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
    })
    .AddCookie(options =>
    {
        options.Events.OnSigningOut = async e =>
        {
            // revoke refresh token on sign-out
            await e.HttpContext.RevokeUserRefreshTokenAsync();
        };
    })
    .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options => {
        options.GetClaimsFromUserInfoEndpoint = true;
        options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;

        options.Authority = Configuration.GetValue<string>("IdentityServer:Authority");
        options.ClientId = Configuration.GetValue<string>("IdentityServer:ClientId");
        options.ClientSecret = Configuration.GetValue<string>("IdentityServer:ClientSecret");
        options.RequireHttpsMetadata = Configuration.GetValue<bool>("IdentityServer:RequireHttpsMetadata");

        options.UsePkce = true;
        options.ResponseType = OidcConstants.ResponseTypes.CodeIdToken;
        options.SaveTokens = true;

        options.TokenValidationParameters = new TokenValidationParameters
        {
            NameClaimType = JwtClaimTypes.Name,
            RoleClaimType = JwtClaimTypes.Role
        };

        // Scopes
        options.Scope.Add("openid");
        options.Scope.Add("offline_access");
    })
    .AddOpenIdConnect("persistent", options => {
        options.CallbackPath = "/signin-persistent";
        options.Events = new OpenIdConnectEvents
        {
            OnRedirectToIdentityProvider = context =>
            {
                context.ProtocolMessage.Prompt = OidcConstants.PromptModes.None;
                return Task.FromResult<object>(null);
            },

            OnMessageReceived = context => {
                if (string.Equals(context.ProtocolMessage.Error, "login_required", StringComparison.Ordinal))
                {
                    context.HandleResponse();
                    context.Response.Redirect("/");
                }
                return Task.FromResult<object>(null);
            }
        };
        
        ...
        // Rest of 'persistent' is similar as the non-persistent one
        ... 
    });
    
// Examples of IdentityModel suggest that calling this function make the boilerplate tasks of refreshing tokens and alike automatically work
services.AddAccessTokenManagement();

内容的提问来源于stack exchange,提问作者Jordy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 02:54:00