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

AccessToken过期未自动登出问题:ASP.NET Core+IdentityServer4+Angular10

IdentityServer4 + Angular oidc-client 令牌过期未自动登出问题解决

问题背景

我手头有个基于ASP.NET Core + IdentityServer4做认证授权的项目,前端用Angular 10搭配oidc-client实现登录逻辑。现在遇到个头疼的问题:明明把AccessToken的有效期设成了5分钟,但用户并不会在令牌过期后自动登出,反而系统会自动静默刷新令牌,让用户一直保持登录状态。目前的配置是AccessTokenLifetime = 5分钟,IdentityServer的CookieSlidingTime = 10分钟,相关代码如下:

前端oidc-client配置

const idServerSettings = {
  authority: Constants.stsAuthority,
  client_id: Constants.clientId,
  scope: 'openid profile',
  response_type: 'code',
  redirect_uri: `${Constants.clientRoot}signin-callback`,
  post_logout_redirect_uri: `${Constants.clientRoot}signout-callback`,
  store: new WebStorageStateStore({ store: localStorage }),
  automaticSilentRenew: true,
  loadUserInfo: true
};

IdentityServer客户端配置

new Client {
  ClientName="test",
  ClientId="client-spa",
  AllowedGrantTypes = GrantTypes.Code,
  AlwaysIncludeUserClaimsInIdToken = true,
  RedirectUris = new List<string>() { "https://localhost:44383/signin-callback" },
  PostLogoutRedirectUris = {"https://localhost:44383/signout-callback" },
  AllowedCorsOrigins = { "https://localhost:44383" },
  AccessTokenLifetime = 60*5, // 5分钟
  AllowedScopes = { IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile, "propel-api" },
  RequireClientSecret=false
}

var builder = services.AddIdentityServer(options => {
  options.Events.RaiseErrorEvents = true;
  options.Events.RaiseInformationEvents = true;
  options.Events.RaiseFailureEvents = true;
  options.Events.RaiseSuccessEvents = true;
  options.UserInteraction.LoginUrl = "/Account/Login";
  options.UserInteraction.LogoutUrl = "/Account/Logout";
  options.Authentication = new AuthenticationOptions() {
    CookieLifetime = TimeSpan.FromMinutes(10),
    CookieSlidingExpiration = true,
  };
}

问题根源

其实这个现象是符合预期的——因为你开启了oidc-client的automaticSilentRenew: true,这个配置会让前端自动检测AccessToken的过期时间,在快过期时悄悄用Refresh Token去IdentityServer申请新的AccessToken。而IdentityServer这边的Cookie设置了10分钟滑动过期,只要用户在10分钟内有交互(包括静默刷新的请求),Cookie就会自动续期,所以静默刷新请求会一直成功,用户自然不会被登出。

解决方案

根据你的需求(希望AccessToken过期后用户登出),可以从以下几个方向调整:

1. 关闭自动静默刷新,或监听过期事件手动登出

如果你不想让系统自动刷新令牌,直接把automaticSilentRenew设为false,这样AccessToken过期后,用户下次发起API请求时会因为令牌无效被拒绝,不过这种方式体验不太友好。

更优雅的方式是保留自动刷新,但监听AccessToken过期事件,一旦过期就触发登出:

const userManager = new UserManager(idServerSettings);

// 监听AccessToken过期事件
userManager.events.addAccessTokenExpired(() => {
  // 触发登出跳转
  userManager.signoutRedirect().catch(err => console.error('登出失败:', err));
});

2. 限制Refresh Token的有效期

默认情况下,IdentityServer的Refresh Token有效期很长(30天),而且是滑动过期的。你可以在Client配置里缩短Refresh Token的有效期,或者改成一次性令牌,让它没法反复刷新:

new Client {
  // ...其他配置
  AccessTokenLifetime = 60*5,
  // 设置Refresh Token有效期和AccessToken一致(5分钟)
  RefreshTokenLifetime = 60*5,
  // 设为一次性令牌,刷新后旧令牌失效
  RefreshTokenUsage = TokenUsage.OneTimeOnly,
  // 绝对过期,不启用滑动刷新
  RefreshTokenExpiration = TokenExpiration.Absolute
}

这样5分钟后,Refresh Token也过期了,静默刷新会失败,前端就能触发登出。

3. 调整IdentityServer的Cookie有效期

你现在的CookieLifetime是10分钟,滑动过期,这意味着用户只要10分钟内有操作,Cookie就会续期。如果希望用户在AccessToken过期后立即登出,可以把Cookie的有效期和AccessToken对齐,或者关闭滑动过期:

options.Authentication = new AuthenticationOptions() {
  // 把Cookie有效期设为5分钟,和AccessToken一致
  CookieLifetime = TimeSpan.FromMinutes(5),
  // 关闭滑动过期,到点就失效
  CookieSlidingExpiration = false,
};

不过这种方式会让用户5分钟不操作就被踢,需要权衡用户体验和安全需求。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 09:22:46