如何配置Keycloak在Token请求URL中添加自定义TOTP字段?
实现Keycloak通过Token端点直接传入自定义TOTP获取Token的方案
默认Keycloak的OpenID Connect Token端点(/auth/realms/{realm}/protocol/openid-connect/token)不支持直接传入自定义TOTP参数,需要通过扩展认证SPI并修改认证流程来实现,具体步骤如下:
1. 开发自定义认证SPI
编写自定义Authenticator,用于读取Token请求中的totp参数并执行自定义验证逻辑:
核心代码示例
public class CustomTotpAuthenticator implements Authenticator { @Override public void authenticate(AuthenticationFlowContext context) { // 从Token请求的表单参数中获取totp值 String totp = context.getHttpRequest().getDecodedFormParameters().getFirst("totp"); if (StringUtils.isBlank(totp)) { context.failure(AuthenticationFlowError.INVALID_CREDENTIALS, context.form().setError("totp-missing").createForm("error-page.ftl")); return; } UserModel user = context.getUser(); // 执行自定义TOTP验证逻辑(比如调用外部验证服务、读取用户存储的密钥验证) boolean isTotpValid = validateCustomTotp(user, totp); if (isTotpValid) { context.success(); } else { context.failure(AuthenticationFlowError.INVALID_CREDENTIALS, context.form().setError("invalid-totp").createForm("error-page.ftl")); } } // 自定义TOTP验证逻辑,根据你的需求实现 private boolean validateCustomTotp(UserModel user, String totp) { // 示例:从用户属性中获取绑定的TOTP密钥,用HMAC算法验证 String secret = user.getFirstAttribute("custom-totp-secret"); if (secret == null) return false; // 这里替换成你的TOTP验证实现,比如用Google Authenticator的算法 return TotpUtils.validateTOTP(secret, totp); } // 实现其他必要的接口方法 @Override public boolean requiresUser() { return true; } @Override public void action(AuthenticationFlowContext context) {} @Override public void close() {} @Override public boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user) { return true; } @Override public void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user) {} }
同时编写对应的AuthenticatorFactory注册SPI,打包成jar后放入Keycloak的providers目录,执行kc.sh build(Windows用kc.bat build)并重启Keycloak。
2. 修改Realm的Direct Grant认证流程
Token端点的密码授权模式依赖Direct Grant流程,需将自定义TOTP验证步骤加入该流程:
- 登录Keycloak管理后台,进入目标Realm(gilgamesh)
- 进入「Authentication」→「Flows」,复制默认的
Direct Grant流程(避免修改默认流程) - 在复制后的流程中,找到
Direct Grant Validator子流程,添加新的执行步骤,选择你开发的自定义TOTP Authenticator - 将该步骤的「Requirement」设置为「REQUIRED」,确保在密码验证后执行TOTP验证
- 进入「Authentication」→「Bindings」,将复制后的流程设置为Realm的默认
Direct Grant Flow
3. 测试Token请求
使用POST请求调用Token端点,传入totp参数即可:
curl -X POST "http://localhost:8082/auth/realms/gilgamesh/protocol/openid-connect/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "username=test-user" \ -d "password=test-pass" \ -d "grant_type=password" \ -d "client_id=your-client-id" \ -d "client_secret=your-client-secret" \ # 保密客户端需要传此参数 -d "totp=123456" # 自定义TOTP值
注意事项
- 自定义TOTP的密钥可存储在Keycloak用户属性中,或关联外部系统的用户TOTP信息
- 需根据Keycloak版本调整SPI代码,不同版本的接口可能有差异
- 错误处理可根据需求自定义错误页面或返回JSON错误信息
内容的提问来源于stack exchange,提问作者LordArnur
相关产品推荐
相关产品推荐

