如何为Keycloak用户添加基于邮箱MD5哈希的程序化自定义字段
实现Keycloak用户创建后自动添加邮箱MD5哈希自定义字段的内置方案
完全可以通过Keycloak的内置扩展能力实现,无需开发包装器,下面提供两种可行的内置方案:
方案一:使用脚本监听器(轻量化,无需编译代码)
这是最快的实现方式,通过Keycloak的脚本扩展能力编写事件监听逻辑:
提前配置自定义用户属性
进入目标Realm的「User Profile」设置,添加一个名为email_md5的自定义属性(如果Keycloak版本默认允许自由添加用户属性,这一步可以跳过)。创建用户注册事件脚本监听器
- 进入Realm的「Events」→「Listeners」页面,点击「Add Listener」,选择类型为
script - 在脚本编辑框中输入以下Groovy代码,监听用户注册事件并生成MD5哈希:
import org.keycloak.events.EventType import org.keycloak.models.UserModel import java.security.MessageDigest import java.math.BigInteger class EmailMD5Listener implements EventListenerProvider { private final KeycloakSession session EmailMD5Listener(KeycloakSession session) { this.session = session } @Override void onEvent(Event event) { if (EventType.REGISTER == event.getType()) { UserModel user = session.users().getUserById(event.userId, session.context.realm) if (user != null && user.email != null) { // 统一邮箱格式(小写+去空格)避免哈希不一致 String normalizedEmail = user.email.toLowerCase().trim() // 计算MD5哈希 MessageDigest md = MessageDigest.getInstance("MD5") byte[] hashBytes = md.digest(normalizedEmail.getBytes()) String md5Hash = new BigInteger(1, hashBytes).toString(16).padLeft(32, '0') // 设置自定义属性 user.setSingleAttribute("email_md5", md5Hash) } } } @Override void onEvent(AdminEvent event, boolean includeRepresentation) {} @Override void close() {} } - 保存并启用该监听器。
- 进入Realm的「Events」→「Listeners」页面,点击「Add Listener」,选择类型为
验证效果
创建新用户,查看该用户的「Attributes」标签页,会自动生成email_md5字段,值为邮箱的MD5哈希。
注意:如果Keycloak默认禁用了脚本支持,需要在配置文件中启用:
- 对于standalone模式,在
standalone.xml中添加/修改:<spi name="scripting"><default-provider>javascript</default-provider><provider name="javascript" enabled="true"/></spi>- 对于容器化部署,设置环境变量
KEYCLOAK_SPI_SCRIPTING_ENABLED=true
方案二:Java SPI扩展(适合复杂逻辑/高性能场景)
如果需要更复杂的业务逻辑或者对性能要求较高,可以开发自定义的Keycloak事件监听器SPI:
创建Java项目
基于Keycloak的SPI接口,实现EventListenerProvider和EventListenerProviderFactory:import org.keycloak.events.Event; import org.keycloak.events.EventListenerProvider; import org.keycloak.events.EventListenerProviderFactory; import org.keycloak.events.EventType; import org.keycloak.models.KeycloakSession; import org.keycloak.models.UserModel; import java.security.MessageDigest; import java.math.BigInteger; public class EmailMD5EventListener implements EventListenerProvider { private final KeycloakSession session; public EmailMD5EventListener(KeycloakSession session) { this.session = session; } @Override public void onEvent(Event event) { if (EventType.REGISTER.equals(event.getType())) { UserModel user = session.users().getUserById(event.getUserId(), session.getContext().getRealm()); if (user != null && user.getEmail() != null) { String normalizedEmail = user.getEmail().toLowerCase().trim(); try { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] hashBytes = md.digest(normalizedEmail.getBytes()); String md5Hash = new BigInteger(1, hashBytes).toString(16).padLeft(32, '0'); user.setSingleAttribute("email_md5", md5Hash); } catch (Exception e) { // 处理哈希计算异常 e.printStackTrace(); } } } } @Override public void onEvent(AdminEvent event, boolean includeRepresentation) {} @Override public void close() {} } // 工厂类 public class EmailMD5EventListenerFactory implements EventListenerProviderFactory { @Override public EventListenerProvider create(KeycloakSession session) { return new EmailMD5EventListener(session); } @Override public void init(org.keycloak.Config.Scope config) {} @Override public void postInit(KeycloakSessionFactory factory) {} @Override public void close() {} @Override public String getId() { return "email-md5-listener"; // 监听器唯一标识 } }打包部署
将项目打包成JAR文件,放到Keycloak的providers目录下,执行kc.sh build(或对应平台的构建命令)后重启Keycloak。启用监听器
在Realm的「Events」→「Listeners」页面,添加并启用email-md5-listener即可。
额外注意事项
- MD5哈希是不可逆的,确保业务场景不需要还原邮箱内容
- 若用户邮箱后续修改,上述方案不会自动更新
email_md5字段,如需支持可以添加对UPDATE_EMAIL事件的监听逻辑 - 自定义属性名称可根据业务需求调整,只需保持代码中的属性名一致即可
内容的提问来源于stack exchange,提问作者Tan Nguyen
相关产品推荐
相关产品推荐

