Keycloak 15.0.2:如何通过SPI无密码创建用户会话并获取令牌?
Keycloak 15.0.2 无密码根据用户ID生成令牌方案
方案一:Token Exchange(标准OIDC流程,推荐)
这是OIDC规范内的标准流程,完全契合Keycloak设计逻辑,无需额外编码,配置即可实现需求,安全可控。
操作步骤:
配置客户端权限
- 登录Keycloak控制台,找到目标Realm下的客户端,在
Advanced标签页开启Token Exchange开关 - 给该客户端分配
impersonation角色:进入客户端Roles标签,将Available Roles里的impersonation添加到Assigned Roles
- 登录Keycloak控制台,找到目标Realm下的客户端,在
获取客户端凭证令牌
先让客户端用自身凭证获取一个access token,作为后续交换的基础凭证:curl -X POST http://{ip}:{port}/auth/realms/{realm}/protocol/openid-connect/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials" \ -d "client_id={你的客户端ID}" \ -d "client_secret={你的客户端密钥}"交换获取用户令牌
用上面拿到的客户端access token,直接交换成目标用户的access/refresh令牌:curl -X POST http://{ip}:{port}/auth/realms/{realm}/protocol/openid-connect/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \ -d "client_id={你的客户端ID}" \ -d "client_secret={你的客户端密钥}" \ -d "subject_token={刚才拿到的客户端access token}" \ -d "subject_token_type=urn:ietf:params:oauth:token-type:access_token" \ -d "requested_subject={目标用户ID}" \ -d "requested_token_type=urn:ietf:params:oauth:token-type:refresh_token" # 加此行可获取refresh令牌,不加仅返回access令牌
方案二:自定义Authenticator SPI(定制化场景)
如果业务有特殊校验逻辑(比如要结合内部系统做额外验证),可以通过自定义SPI实现无密码登录。
操作步骤:
编写自定义Authenticator
实现Keycloak的Authenticator接口,核心逻辑是直接根据用户ID查找用户并创建会话:public class NoPasswordAuthenticator implements Authenticator { @Override public void authenticate(AuthenticationFlowContext context) { // 从请求参数或自定义Header获取用户ID String userId = context.getHttpRequest().getDecodedFormParameters().getFirst("user_id"); if (userId == null) { context.failure(AuthenticationFlowError.INVALID_CREDENTIALS); return; } UserModel user = context.getSession().users().getUserById(userId, context.getRealm()); if (user == null) { context.failure(AuthenticationFlowError.USER_NOT_FOUND); return; } // 直接标记认证成功,创建用户会话 context.setUser(user); context.success(); } // 以下为必须实现的默认逻辑或空方法 @Override public void action(AuthenticationFlowContext context) {} @Override public boolean requiresUser() { return false; } @Override public boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user) { return true; } @Override public void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user) {} @Override public void close() {} }打包部署SPI
将代码打包成JAR文件,放到Keycloak的standalone/deployments目录下,等待Keycloak自动加载。配置认证流程
- 在Keycloak控制台
Authentication菜单中,复制现有流程(如browser流程)并命名为no-password-login - 替换流程内的
Username Password Form为自定义的Authenticator - 将该流程绑定到目标客户端(在客户端的
Authentication Flow Overrides中设置)
- 在Keycloak控制台
调用获取令牌
用类似密码流的方式,传入user_id参数即可:curl -X POST http://{ip}:{port}/auth/realms/{realm}/protocol/openid-connect/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=password" \ -d "client_id={你的客户端ID}" \ -d "client_secret={你的客户端密钥}" \ -d "user_id={目标用户ID}"
方案对比
- Token Exchange:零编码成本,配置简单,完全遵循标准规范,安全可靠,适合绝大多数通用场景。
- 自定义SPI:适配特殊业务逻辑需求,但需要开发和维护SPI代码,整体成本更高。
内容的提问来源于stack exchange,提问作者M.Surnyk
相关产品推荐
相关产品推荐

