keycloak~refresh_token的深度总结

内容大纲

  1. keycloak关于会话有效期的配置
  2. refresh_token作用
  3. refresh_token使用规范
  4. keycloak开启refresh_token的限制
  5. refresh_token时的错误汇总
  6. keycloak中refresh_token的底层逻辑
  7. session过期时间的清除策略

一 keycloak关于会话有效期的配置

1. session配置说明及推荐配置`

参数名称 推荐配置 说明
Access Token Lifespan 5分钟(300秒) access_token的有效期。
SSO Session Idle 7天(604800秒) 用户会话的空闲时间。
SSO Session Max 1年(31536000秒) 用户会话的最大持续时间。
Client Session Idle 7天(604800秒) 客户端会话的空闲时间。
Client Session Max 1年(31536000秒) 客户端会话的最大持续时间。
Offline Session Idle 7天(604800秒) 离线会话的空闲时间(可选)。
Offline Session Max 1年(31536000秒) 离线会话的最大持续时间(可选)。
SSO Session Idle Remember Me 7天(604800秒) “记住我”会话的空闲时间(可选)。
SSO Session Max Remember Me 1年(31536000秒) “记住我”会话的最大持续时间(可选)。

2. 会话最后更新时间(这对session idle会产生影响)

  • 去登录页换取授权码后,这个时间会更新
  • 刷新token时,这个时间会更新
  • 主动调用introspect验证access_token有效性时,这个时间会更新
  • 授权码登录,code换token时,这个时间不更新
  • 使用access_token访问具体资源时,这个时间不更新

3. code换token时去掉client限制引发的问题

  • 当我们通过客户端a申请授权码code后,我们使用客户端b获取了access_token和refresh_token
  • 这时,我们通过refresh_token来刷新token时,是不成功的,会有两种场景错误
    1. 当你使用客户端a来刷新token时,会出现Unmatching clients 400错误
    2. 当你使用客户端b来刷新token时,会出现Session doesn't have required client 400错误
  • 所以,否建议把code换token时client_id的限制去掉,这就引发刷新token的问题

二 refresh_token作用

1. 主要作用

refresh_token是用来刷新access_token的,当access_token过期后,可以通过refresh_token来获取新的access_token,而不需要重新登录。

2. 动态会话续期规则

  • SSO Session Max的限制:
    • 无论用户如何活跃或使用refresh_token,会话的总持续时间不能超过SSO Session Max。
    • 例如,如果SSO Session Max设置为1年,即使用户每天都在使用App,1年后会话也会过期,用户需要重新登录。
  • SSO Session Idle的限制:
    • 如果用户在SSO Session Idle时间内没有任何操作,会话将过期,即使用户使用refresh_token也无法续期。

三 refresh_token使用规范

1. 使用方法

curl --location --request POST 'https://{keycloak}/auth/realms/{realm}/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=refresh_token' \
--data-urlencode 'refresh_token={refresh_token}' \
--data-urlencode 'client_id={client_id}' \
--data-urlencode 'client_secret={client_secret}'

**2. 使用规范

  • 每个refresh_token只能使用一次,不可重复使用,KC这边也会进行回收它
  • 通过refresh_token获取新的token时,返回值里会带有新的refresh_token,我们应该使用新的refresh_token来覆盖上一次的refresh_token
  • refresh_token有效期取决于keycloaktokenssso session idle的值,即会话空闲时间,如果refresh_token在这个时间内没有使用,那么它会失效
  • refresh_token失效后,当前会话session_state也即失效,此时,需要重新登录

注意:sso session max表示会话最大有效期,在这个时间范围内,用户不需要重新登录,sso session idle表示会话空闲时间,在这个时间内用户不进行操作,会话也会过期(在下次用户主动刷新token时,这个会话将会从keycloak后台会话管理中删除),session max表示最大会话时间,相当于会话在缓存里的有效期,到期后自动清除(缓存自身的特性,不需要keycloak干预;而离线会话由于是存储到mysql的,这块是通过任务调度进行清理的),这两种情况满足后,用户都需要重新登录,这两个值必须大于0;单位为分,小时,天,不支持永久有效期。

用户在刷新token时,如果会话已经失效(session idle到期,而不是session max到期,后者会自动清理),则删除它(而不是keycloak主动检查的)

四 keycloak开启refresh_token的限制

五 refresh_token时的错误汇总

  • 当refresh_token超过限制时,会返回invalid_grant错误,此时,需要重新登录

  • 再次使用refresh_token,同样返回状态码400,但返回消息体会有变化

  • 如果当前session已经失效,即会话达到了session max的时间,将返回下面错误

  • 如果当前客户端与token客户端不一致,将返回下面错误

  • 如果当前当前端开启了同意许可,将返回下面错误

六 keycloak中refresh_token的底层逻辑

  1. validateToken方法

  2. 通过session_state获取userSession对象,如果userSession对象为空,说明refresh_token已经失效,返回400 Session not active

  3. isSessionValid方法主要验证会话是否有效,主要判断以下几个部分

  • 用户会话是否存在,user-session是否存在
  • 获取session空闲时间和最大时间,它们的逻辑与是否开启记住我有关
  • 会有两层时间的比较,来确定session是否有效
    • 第一层,session空闲时间是否大于(当前时间-最后刷新token时间-容错窗口期(120秒))
    • 第二层,session最大时间是否大于(当前时间-session开始时间)
  • 上面两层同时满足,说明session是有效的
  1. 从userSession中获取当前用户对象
  2. 判断用户是否有效
    • 如果用户被删除,返回400 Unknown user
    • 如果用户状态为禁用,返回400 User disabled
    • 如果用户需要一个必要的行为,返回400 User has required action
  3. 判断当前refresh_token的建立时间是否早于会话开始时间,正常情况下肯定是晚于会话时间,如果早于,返回400 Refresh toked issued before the user session started
  4. 判断当前userSession是否在当前client_id对应的clientSession里,如果没有,返回400 Session doesn't have required client
  5. 判断当前refresh_token里的azp是否与请求参数client_id相同,不同返回400 Unmatching clients
  6. 验证refresh_token是否被篡改
  7. 检查客户端是否有consent的授权许可同意,如果开启了,会返回400 Client no longer has requested consent from user
  8. 成功建立新的token对象,整个刷新token流程结束
{
    "access_token": "",
    "expires_in": 120,
    "refresh_expires_in": 300,
    "refresh_token": "",
    "token_type": "Bearer",
    "id_token": "",
    "not-before-policy": 1740449130,
    "session_state": "424b8022-600d-421e-a45d-e0315d1a524d",
    "scope": "openid roles email profile"
}

七 session过期时间的清除策略

1. 普通会话

  • 通过infinispan缓存里的过期时间自动管理,到期后,自动清除

2. 离线会话

  • keycloak通过定时器,实现离线会话的清理,它存到mysql中,这是没有过期时间可言的,可查看offline_user_session相关的内容
  • org.keycloak.services.scheduled.ScheduledTaskRunner # 默认900秒(15分钟)执行一次
    • org.keycloak.services.scheduled.ClearExpiredUserSessionsTask
      • org.keycloak.models.map.authSession.removeExpired
posted @   张占岭  阅读(98)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示
历史上的今天:
2021-02-25 springboot~某个接口模拟登录并同步给feign
点击右上角即可分享
微信分享提示