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

Spring-Boot+Angular+Keycloak PKCE授权码流重复获取AccessToken问题

问题分析与解决方案

先明确核心结论:OAuth2的授权码规范要求同一个授权码只能用一次,所以你说的“重复用同一授权码获取新token”绝对不是正常行为——要么是你误解了Keycloak适配器的操作流程,要么是配置出了问题。

1. 刷新/跳转页面重复走第三步的原因

你当前配置的onLoad: 'login-required',会让Keycloak的JS适配器在页面加载时强制校验认证状态:

  • 如果适配器在本地找不到有效的token(比如没开持久化、token过期),就会触发认证流程;
  • 但因为Keycloak已经通过会话Cookie识别了你是已登录状态,所以会直接跳过登录页,返回新的授权码(不是旧的),再用这个新码去换token。

你误以为是同一授权码,大概率是没注意每次的code参数都是不一样的——抓包看一下就清楚了。如果真的是同一个授权码被重复使用,Keycloak应该直接返回invalid_grant错误,那你就得检查Keycloak客户端的安全配置了。

2. 实现“一次获取token重复使用”的配置

要让适配器把token存在本地,避免每次刷新都重新走授权流程,需要给initOptions加两个关键配置:

function initializeKeycloak(keycloak: KeycloakService) {
  return () =>
    keycloak.init({
      config: {
        url: environment.keycloakurl,
        realm: 'realm',
        clientId: 'client',
      },
      initOptions: {
        onLoad: 'login-required',
        // 把token存在sessionStorage里,浏览器关闭就清除,也可以选localStorage持久化
        tokenStorage: 'sessionStorage',
        // 配置静默刷新的跳转页面,token快过期时自动刷新,不用用户操作
        silentCheckSsoRedirectUri: window.location.origin + '/assets/silent-check-sso.html'
      }
    });
}

另外要在Angular项目的assets文件夹下创建silent-check-sso.html文件,内容如下:

<!DOCTYPE html>
<html>
<body>
  <script>
    parent.postMessage(location.href, location.origin);
  </script>
</body>
</html>

3. 必须注意的安全细节

  • 授权码一次性验证:Keycloak默认是开着这个机制的,绝对别关,不然授权码被别人拿到就能重复换token,完全违反OAuth2的安全设计;
  • token存储选择:sessionStorage比localStorage更安全,因为关闭浏览器就清掉了,适合不需要“记住我”的场景;如果要用户下次打开浏览器还能自动登录,再选localStorage;
  • 静默刷新:配了silentCheckSsoRedirectUri之后,适配器会在token快过期时自动发起静默授权,偷偷换好新token,用户完全没感知。

如果确认真的是同一授权码被重复用,去Keycloak控制台检查:
进入你的Realm → 客户端 → 你的客户端 → 高级设置 → 授权码策略,确保选的是「一次性」(One Time Use)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 08:37:20