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

Keycloak 15.0.2:如何通过SPI无密码创建用户会话并获取令牌?

Keycloak 15.0.2 无密码根据用户ID生成令牌方案

方案一:Token Exchange(标准OIDC流程,推荐)

这是OIDC规范内的标准流程,完全契合Keycloak设计逻辑,无需额外编码,配置即可实现需求,安全可控。

操作步骤:

  1. 配置客户端权限

    • 登录Keycloak控制台,找到目标Realm下的客户端,在Advanced标签页开启Token Exchange开关
    • 给该客户端分配impersonation角色:进入客户端Roles标签,将Available Roles里的impersonation添加到Assigned Roles
  2. 获取客户端凭证令牌
    先让客户端用自身凭证获取一个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={你的客户端密钥}"
    
  3. 交换获取用户令牌
    用上面拿到的客户端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实现无密码登录。

操作步骤:

  1. 编写自定义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() {}
    }
    
  2. 打包部署SPI
    将代码打包成JAR文件,放到Keycloak的standalone/deployments目录下,等待Keycloak自动加载。

  3. 配置认证流程

    • 在Keycloak控制台Authentication菜单中,复制现有流程(如browser流程)并命名为no-password-login
    • 替换流程内的Username Password Form为自定义的Authenticator
    • 将该流程绑定到目标客户端(在客户端的Authentication Flow Overrides中设置)
  4. 调用获取令牌
    用类似密码流的方式,传入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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 00:01:20