如何基于Keycloak实现高并发场景下的访客登录?
问题描述
我正在API中用Keycloak实现访客登录功能,操作步骤如下:
- 创建了一个仅拥有最小权限的访客角色及对应访客用户;
- 用户选择访客登录时,需提供真实邮箱(比如
user1@example.com); - API使用访客凭据向Keycloak发起认证请求,同时传递该真实邮箱。
发起认证的请求代码如下:
var authRequestParameters = new KeyValuePair<string, string>[] { new("client_id", "my-client"), new("client_secret", "my-secret"), new("scope", "openid"), new("grant_type", "password"), new("username", "guest_user"), new("password", "guest_password_XXXXX"), new("guest_email", "user1@example.com") // 自定义字段 };
我期望返回的JWT令牌中包含guest_email声明,但实际并未出现:
{ ---移除多余信息--- "name": "Guest Guest", "guest_email": "user1@example.com" -- 缺失 }
我试过用User Session Note Mappers,但没达到预期;也了解过自定义protocol mappers,但不确定最优实现方式。
注意:同一访客账号会被多用户同时使用,解决方案必须支持高并发,确保会话数据不会互相覆盖,相关信息需存储在令牌层面,而非Keycloak数据库中。
具体问题
- 访客登录时,如何在JWT中传递并获取真实邮箱?
- 多用户环境下,如何实现无会话数据冲突的方案?
- 有没有更好的Keycloak访客登录实现方案?各有哪些优缺点?
解决方案
1. 在JWT中传递并获取真实邮箱
要把自定义的guest_email字段加入JWT,需使用自定义Script Protocol Mapper,确保数据仅存于当前令牌、不写入Keycloak数据库,步骤如下:
- 登录Keycloak控制台,进入目标Realm → 客户端 → 你的客户端(
my-client)→ Mappers标签页; - 点击「Create」,选择Script Mapper类型;
- 配置参数:
- Name: 例如
guest_email_mapper - Script Type:
Token Mapper - Token Type:
Access Token(若需ID Token也包含,可新增同配置的Mapper选择ID Token) - Script内容:
// 从当前认证请求中提取自定义参数guest_email var guestEmail = session.getContext().getRequest().getFormParam("guest_email"); if (guestEmail) { // 将字段写入Access Token accessToken.setClaim("guest_email", guestEmail); // 如需写入ID Token,添加此行: // idToken.setClaim("guest_email", guestEmail); }
- Name: 例如
- 保存后重新发起认证请求,JWT中即可包含
guest_email声明。
User Session Note Mappers不可用的原因:它会把数据存入用户会话,同一访客账号被多人同时登录时,会话数据会被覆盖,不符合高并发要求。而Script Mapper直接从当前请求取参数写入令牌,每个令牌独立存储,无冲突风险。
2. 多用户环境下无会话冲突的实现
核心原则是不共享会话数据,所有访客自定义信息仅存于各自的JWT令牌中,不写入Keycloak的用户会话或用户实体:
- 采用上述Script Mapper方案,直接从请求参数提取
guest_email写入令牌,每个请求生成的令牌独立,不会互相覆盖; - 禁止使用修改用户会话或用户属性的操作(如User Session Notes、User Attribute Mappers),这类操作会导致并发访问时的数据冲突;
- 合理设置Keycloak客户端的会话超时时间,避免旧会话残留,但因我们不依赖会话存储数据,即使会话复用,令牌内的
guest_email仍保持独立。
3. 其他Keycloak访客登录方案及优缺点
方案一:一次性临时用户
- 实现:用户选择访客登录时,API调用Keycloak Admin API动态创建带邮箱、最小权限的临时用户,登录后自动定时删除;
- 优点:每个访客拥有独立账号,数据隔离性好,完全契合Keycloak原生用户模型;
- 缺点:需具备Admin API权限,高并发下创建/删除用户存在性能开销,Keycloak用户存储压力大,需额外做过期用户清理。
方案二:Client Credentials Flow + 自定义声明
- 实现:API使用Client Credentials Flow获取令牌,请求时传递访客邮箱,通过Script Mapper将邮箱写入令牌;
- 优点:无需创建访客用户,流程简单,高并发友好,令牌数据完全独立;
- 缺点:无法区分不同访客的会话(需额外添加标识),权限控制仅能基于客户端,无法实现细粒度访客权限区分。
方案三:Authorization Code Flow + 匿名身份
- 实现:开启Keycloak匿名身份功能,访客无需登录直接获取匿名令牌,再通过API补充邮箱信息到令牌;
- 优点:无需共享账号,原生支持匿名访问,流程更规范;
- 缺点:需配置匿名身份提供者,额外的令牌补充步骤增加复杂度,匿名权限配置较繁琐。
当前方案(共享访客账号+Script Mapper)的优缺点:
- 优点:无需额外用户管理,性能开销小,高并发友好;
- 缺点:无法区分不同访客的用户级操作(如记录访客行为只能依赖令牌内的邮箱),Keycloak用户登录日志会混杂所有访客记录。
内容的提问来源于stack exchange,提问作者Masood Ahmad
相关产品推荐
相关产品推荐

