在Keycloak邮件主题中使用username变量失败的问题求助
环境
- Bitnami部署的Keycloak v24.0.5
- Kubernetes v1.30.0
已实现功能
为了在密码变更通知邮件正文中插入username,我创建了自定义主题并通过Docker镜像部署:
FROM docker.io/bitnami/keycloak:24.0.5-debian-12-r1 USER root COPY my-custom-theme /opt/bitnami/keycloak/themes/my-custom-theme USER 1001
修改了主题内的event-update_password.ftl模板:
<#ftl output_format="plainText"> ${msg("eventUpdatePasswordBody",user.getUsername(), event.date, event.ipAddress)}
同步更新了messages_en.properties中的消息定义:
eventUpdatePasswordBody=Dear {0} your password was changed on {1} from {2}. If this was not you, please contact an administrator. eventUpdatePasswordBodyHtml=<p>Dear {0} your password was changed on {1} from {2}. If this was not you, please contact an administrator.</p>
此配置正常生效,邮件正文能正确将{0}替换为用户名。
问题描述
尝试在邮件主题中加入用户名,修改messages_en.properties:
eventUpdatePasswordSubject=Update password {0}
但邮件主题未解析变量,收到的邮件标题直接显示Update password {0},未替换为实际用户名。注意到默认配置里的identityProviderLinkSubject=Link {0}能正常解析变量,不清楚哪里遗漏了配置。
原因与解决方法
核心问题是:Keycloak中邮件主题的变量解析逻辑和正文不同。正文是通过FTL模板主动调用msg()方法传递参数,但主题的参数传递是由发送邮件的Java业务代码决定的。
对于UPDATE_PASSWORD事件,Keycloak默认代码并没有给主题消息传递用户名参数;而identityProviderLink事件的代码中明确传递了参数,所以后者能正常解析变量。
解决方式
自定义事件监听器SPI扩展
创建实现EventListenerProvider的类,监听UPDATE_PASSWORD事件,在处理逻辑中获取用户对象,调用邮件发送服务时手动将用户名作为参数传递给主题消息。- 编写扩展代码,打包为JAR
- 将JAR放入Keycloak的
providers目录(Bitnami镜像中路径为/opt/bitnami/keycloak/providers/) - 在Keycloak管理后台启用该自定义事件监听器
检查主题模板是否支持主题参数传递
部分Keycloak版本中,邮件主题可能由特定FTL模板生成,但v24版本中UPDATE_PASSWORD事件的主题通常直接读取消息属性,无模板传递参数,因此SPI扩展是更可靠的方案。
内容的提问来源于stack exchange,提问作者Michał Lewndowski

