← 返回统一认证中心

如何定制 Keycloak Realm 登录页面

2026-06-12 · Keycloak 26.x

Keycloak 默认登录页比较朴素,好在它提供了完善的主题机制,可以自由定制登录、注册、忘记密码等页面样式。本文以 Keycloak 26.x 为例,介绍从零开始定制一个 Realm 登录页的完整流程。

1. 主题目录结构

Keycloak 主题存放在 themes/ 目录下。创建一个自定义主题的最小结构:

themes/
└── my-theme/
    ├── theme.properties          # 主题根配置
    └── login/
        ├── theme.properties      # 登录页配置
        ├── login.ftl             # 登录页模板
        ├── messages/
        │   └── messages_zh_CN.properties  # 中文本地化
        └── resources/
            └── css/
                └── login.css     # 样式文件

2. 核心配置文件

theme.properties(主题根目录)

parent=keycloak

parent=keycloak 表示继承 Keycloak 内置主题。未自定义的部分(如注册页、邮件模板)会自动使用父主题。

login/theme.properties

parent=keycloak
styles=css/login.css

这里引入自定义 CSS 文件。可以列出多个样式文件,用空格分隔。

3. FreeMarker 模板

Keycloak 使用 Apache FreeMarker 作为模板引擎。登录页的核心是 login.ftl

<#import "template.ftl" as layout>
<@layout.registrationLayout displayInfo=true; section>
  <#if section = "header">
    <#-- 留空,我们自己写 header -->
  <#elseif section = "form">
    <div class="kc-login-card">
      <div class="kc-brand">
        <h1>${msg("loginTitleHtml")}</h1>
        <p>${msg("loginAccountTitle")}</p>
      </div>

      <form action="${url.loginAction}" method="post">
        <div class="kc-field">
          <label for="username">${msg("usernameOrEmail")}</label>
          <input id="username" name="username" type="text"
                 value="${(login.username!'')}">
        </div>
        <div class="kc-field">
          <label for="password">${msg("password")}</label>
          <input id="password" name="password" type="password">
        </div>
        <button type="submit">${msg("doLogIn")}</button>
      </form>
    </div>
  </#if>
</@layout.registrationLayout>
重要:Keycloak 父模板会在你的 FTL 外面包裹一层 <div class="card-pf">,写 CSS 时要注意把外层重置为透明,避免双层卡片嵌套。

4. 中文本地化

login/messages/messages_zh_CN.properties 中定义中文文本:

doLogIn=登 录
doRegister=注 册
usernameOrEmail=用户名或邮箱
username=用户名
password=密码
forgotPassword=忘记密码?
noAccount=还没有账号?
registerNow=立即注册
loginTitle=登录
loginTitleHtml=登录
loginAccountTitle=使用火金科技账号

同时需要在 Keycloak Admin 中为 Realm 启用国际化:

  1. 进入 Realm Settings → Localization
  2. 开启 Internationalization
  3. 设置默认语言为 zh-CN
  4. 添加支持的语言:zh-CNen

5. CSS 样式要点

Keycloak 页面结构是 <html class="login-pf"><div class="login-pf-page"><div class="card-pf">你的 kc-login-card

写 CSS 时需要注意:

推荐做法:

/* 重置外层 */
.card-pf {
  background: transparent;
  border: none;
  box-shadow: none;
  padding: 0;
  width: 100%;
  max-width: 400px;
}

/* 你的卡片 */
.kc-login-card {
  background: #fff;
  border-radius: 16px;
  padding: 48px 40px;
  box-shadow: 0 1px 3px rgba(0,0,0,0.04), 0 8px 24px rgba(0,0,0,0.06);
}

/* 隐藏默认元素 */
#kc-header, #kc-header-wrapper,
#kc-locale { display: none !important; }

6. 部署方式

推荐使用 bind mount 将主题目录挂载到 Keycloak 容器:

docker run ... \
  -v /opt/workspace/themes/my-theme:/opt/keycloak/themes/my-theme:ro

这样主题文件放在宿主机上,可以用 Git 管理版本:

# 宿主机
cd /opt/workspace/themes/my-theme
git pull   # 更新主题

# 重启 Keycloak 使主题生效
docker restart keycloak

Keycloak 会缓存主题资源(CSS/JS),更新后需要重启容器清除缓存。

7. 在 Realm 中启用主题

通过 Admin Console:Realm Settings → Themes → Login Theme,选择你的主题名称。

或者通过 API:

curl -X PUT https://auth.example.com/admin/realms/{realm} \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"loginTheme":"my-theme"}'

常见问题

修改不生效?

页面布局错乱?

中文乱码或不显示?