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

如何获取AspNetCore.Identity.Application Cookie的过期时间或最大存活期

获取AspNetCore.Identity.Application Cookie剩余过期时间的实现方案

为什么直接从Request.Cookies拿不到过期时间

  • 你配置了options.Cookie.HttpOnly = true,浏览器会禁止前端JS访问Cookie的元数据(过期时间、MaxAge等);同时服务器端的Request.Cookies集合仅存储Cookie的值,不包含任何属性信息。
  • 开启SlidingExpiration = true后,Cookie的过期时间会随每次请求动态更新,更无法直接从静态配置中获取实时剩余时长。

可行实现方案

方案一:通过用户Claim跟踪过期时间

1. 登录时注入过期时间Claim

在登录接口中,登录成功后计算Cookie过期时间并添加到用户Claims中:

// 注入依赖
private readonly SignInManager<IdentityUser> _signInManager;
private readonly UserManager<IdentityUser> _userManager;
private readonly IOptions<CookieAuthenticationOptions> _cookieOptions;

public async Task<IActionResult> Login(LoginViewModel model)
{
    var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
    if (result.Succeeded)
    {
        var user = await _userManager.FindByEmailAsync(model.Email);
        var expireTime = DateTime.UtcNow.Add(_cookieOptions.Value.ExpireTimeSpan);
        
        // 移除旧的过期时间Claim(如果存在)
        var oldClaim = (await _userManager.GetClaimsAsync(user)).FirstOrDefault(c => c.Type == "CookieExpireTime");
        if (oldClaim != null)
        {
            await _userManager.RemoveClaimAsync(user, oldClaim);
        }
        
        // 添加新的过期时间Claim
        await _userManager.AddClaimAsync(user, new Claim("CookieExpireTime", expireTime.ToString("o")));
        
        // 刷新登录状态,使新Claim生效
        await _signInManager.RefreshSignInAsync(user);
        
        return RedirectToAction("Index", "Home");
    }
    // 登录失败处理逻辑...
}

2. 在_Layout.cshtml中读取并展示剩余时长

@inject IHttpContextAccessor httpContextAccessor;

@{
    var expireClaim = httpContextAccessor.HttpContext.User.Claims.FirstOrDefault(c => c.Type == "CookieExpireTime");
    string remainingTimeText = string.Empty;
    
    if (expireClaim != null && DateTime.TryParse(expireClaim.Value, out DateTime expireTime))
    {
        var remainingTime = expireTime - DateTime.UtcNow;
        if (remainingTime > TimeSpan.Zero)
        {
            remainingTimeText = $"剩余登录时长: {remainingTime.Minutes} 分 {remainingTime.Seconds} 秒";
        }
        else
        {
            remainingTimeText = "登录已过期";
        }
    }
}

<!-- 在导航栏合适位置插入 -->
<div>@remainingTimeText</div>

3. 处理滑动过期的实时更新

开启滑动过期后,每次请求若剩余时间小于过期时长的一半,Cookie会自动延期。此时需要同步更新Claim中的过期时间,写一个中间件处理:

public class CookieExpirationMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IOptions<CookieAuthenticationOptions> _cookieOptions;
    private readonly SignInManager<IdentityUser> _signInManager;
    private readonly UserManager<IdentityUser> _userManager;

    public CookieExpirationMiddleware(RequestDelegate next, IOptions<CookieAuthenticationOptions> cookieOptions, SignInManager<IdentityUser> signInManager, UserManager<IdentityUser> userManager)
    {
        _next = next;
        _cookieOptions = cookieOptions;
        _signInManager = signInManager;
        _userManager = userManager;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        if (context.User.Identity.IsAuthenticated)
        {
            var expireClaim = context.User.Claims.FirstOrDefault(c => c.Type == "CookieExpireTime");
            if (expireClaim != null && DateTime.TryParse(expireClaim.Value, out DateTime expireTime))
            {
                var timeUntilExpire = expireTime - DateTime.UtcNow;
                // 匹配Cookie滑动过期逻辑:剩余时间小于过期时长一半时触发延期
                if (timeUntilExpire < _cookieOptions.Value.ExpireTimeSpan / 2)
                {
                    var user = await _userManager.GetUserAsync(context.User);
                    var newExpireTime = DateTime.UtcNow.Add(_cookieOptions.Value.ExpireTimeSpan);
                    
                    await _userManager.RemoveClaimAsync(user, expireClaim);
                    await _userManager.AddClaimAsync(user, new Claim("CookieExpireTime", newExpireTime.ToString("o")));
                    await _signInManager.RefreshSignInAsync(user);
                }
            }
        }

        await _next(context);
    }
}

在Program.cs中注册中间件(需放在认证中间件之后):

app.UseAuthentication();
app.UseAuthorization();

// 注册自定义中间件
app.UseMiddleware<CookieExpirationMiddleware>();

方案二:通过Session存储过期时间

如果不想修改用户Claims,也可以用Session临时存储过期时间:

1. 登录时写入Session

if (result.Succeeded)
{
    var expireTime = DateTime.UtcNow.Add(_cookieOptions.Value.ExpireTimeSpan);
    HttpContext.Session.SetString("CookieExpireTime", expireTime.ToString("o"));
    return RedirectToAction("Index", "Home");
}

2. 在_Layout.cshtml中读取

@inject IHttpContextAccessor httpContextAccessor;

@{
    var expireTimeStr = httpContextAccessor.HttpContext.Session.GetString("CookieExpireTime");
    string remainingTimeText = string.Empty;
    
    if (!string.IsNullOrEmpty(expireTimeStr) && DateTime.TryParse(expireTimeStr, out DateTime expireTime))
    {
        var remainingTime = expireTime - DateTime.UtcNow;
        if (remainingTime > TimeSpan.Zero)
        {
            remainingTimeText = $"剩余登录时长: {remainingTime.Minutes} 分 {remainingTime.Seconds} 秒";
        }
        else
        {
            remainingTimeText = "登录已过期";
        }
    }
}

<div>@remainingTimeText</div>

同样需要在中间件中处理滑动过期时的Session更新逻辑,操作逻辑和方案一类似,仅需把Claim操作替换为Session操作即可。

注意事项

  • 必须使用DateTime.UtcNow计算时间,避免时区差异导致的时长计算错误。
  • 若使用Claim方案,要确保用户Claims的存储支持动态更新(EF Core的Identity存储默认支持)。
  • 滑动过期的判断逻辑要和Cookie配置的SlidingExpiration逻辑保持一致,确保展示的剩余时间和实际Cookie过期时间同步。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 05:45:06