English 中文(简体)
Keycloak custom theme reject login.ftl
原标题:
  • 时间:2020-02-12 12:05:10
  •  标签:
  • keycloak

I create custom keycloak login screen.

I download from keycloak web page

Server Standalone server distribution

And copy from keycloak-8.0.2 hemeskeycloak to C:xxconfigurationkeycloak hememy-theme And there I open login folder and there I have

- theme.properties
- resources

In resources, I change login.css and everything is working, I can change colors, img etc...

Until now, in folder login I didn t have login.ftl and I take and copy one from keycloak downloaded files. But now, when I try to load my page I get

This page isn’t working 
localhost.test.net is currently unable to handle this request.
HTTP ERROR 500

If I remove this file, everything is working.

I need this file to change some things in html

here is theme.properties file

parent=base
import=common/keycloak

styles=node_modules/patternfly/dist/css/patternfly.min.css node_modules/patternfly/dist/css/patternfly-additions.min.css lib/zocial/zocial.css css/login.css
meta=viewport==width=device-width,initial-scale=1

kcHtmlClass=login-pf
kcLoginClass=login-pf-page

kcLogoLink=http://www.keycloak.org

kcLogoClass=login-pf-brand

kcContainerClass=container-fluid
kcContentClass=col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3 col-lg-6 col-lg-offset-3
kcContentWrapperClass=row

kcHeaderClass=login-pf-page-header
kcFeedbackAreaClass=col-md-12
kcLocaleClass=col-xs-12 col-sm-1
kcAlertIconClasserror=pficon pficon-error-circle-o

kcFormAreaClass=col-sm-10 col-sm-offset-1 col-md-8 col-md-offset-2 col-lg-8 col-lg-offset-2
kcFormCardClass=card-pf
kcFormCardAccountClass=login-pf-accounts
kcFormSocialAccountClass=login-pf-social-section
kcFormSocialAccountContentClass=col-xs-12 col-sm-6
kcFormSocialAccountListClass=login-pf-social list-unstyled login-pf-social-all
kcFormSocialAccountDoubleListClass=login-pf-social-double-col
kcFormSocialAccountListLinkClass=login-pf-social-link
kcFormHeaderClass=login-pf-header

kcFeedbackErrorIcon=pficon pficon-error-circle-o
kcFeedbackWarningIcon=pficon pficon-warning-triangle-o
kcFeedbackSuccessIcon=pficon pficon-ok
kcFeedbackInfoIcon=pficon pficon-info


kcFormClass=form-horizontal
kcFormGroupClass=form-group
kcFormGroupErrorClass=has-error
kcLabelClass=control-label
kcLabelWrapperClass=col-xs-12 col-sm-12 col-md-12 col-lg-12
kcInputClass=form-control
kcInputWrapperClass=col-xs-12 col-sm-12 col-md-12 col-lg-12
kcFormOptionsClass=col-xs-12 col-sm-12 col-md-12 col-lg-12
kcFormButtonsClass=col-xs-12 col-sm-12 col-md-12 col-lg-12
kcFormSettingClass=login-pf-settings
kcTextareaClass=form-control
kcSignUpClass=login-pf-signup


kcInfoAreaClass=col-xs-12 col-sm-4 col-md-4 col-lg-5 details

##### css classes for form buttons
# main class used for all buttons
kcButtonClass=btn
# classes defining priority of the button - primary or default (there is typically only one priority button for the form)
kcButtonPrimaryClass=btn-primary
kcButtonDefaultClass=btn-default
# classes defining size of the button
kcButtonLargeClass=btn-lg
kcButtonBlockClass=btn-block

##### css classes for input
kcInputLargeClass=input-lg

##### css classes for form accessability
kcSrOnlyClass=sr-only

And here is login.ftl

<#import "template.ftl" as layout>
<@layout.registrationLayout displayInfo=social.displayInfo displayWide=(realm.password && social.providers??); section>
    <#if section = "header">
        ${msg("doLogIn")}
    <#elseif section = "form">
    <div id="kc-form" <#if realm.password && social.providers??>class="${properties.kcContentWrapperClass!}"</#if>>
      <div id="kc-form-wrapper" <#if realm.password && social.providers??>class="${properties.kcFormSocialAccountContentClass!} ${properties.kcFormSocialAccountClass!}"</#if>>
        <#if realm.password>
            <form id="kc-form-login" onsubmit="login.disabled = true; return true;" action="${url.loginAction}" method="post">
                <div class="${properties.kcFormGroupClass!}">
                    <label for="username" class="${properties.kcLabelClass!}"><#if !realm.loginWithEmailAllowed>${msg("username")}<#elseif !realm.registrationEmailAsUsername>${msg("usernameOrEmail")}<#else>${msg("email")}</#if></label>

                    <#if usernameEditDisabled??>
                        <input tabindex="1" id="username" class="${properties.kcInputClass!}" name="username" value="${(login.username!  )}" type="text" disabled />
                    <#else>
                        <input tabindex="1" id="username" class="${properties.kcInputClass!}" name="username" value="${(login.username!  )}"  type="text" autofocus autocomplete="off" />
                    </#if>
                </div>

                <div class="${properties.kcFormGroupClass!}">
                    <label for="password" class="${properties.kcLabelClass!}">${msg("password")}</label>
                    <input tabindex="2" id="password" class="${properties.kcInputClass!}" name="password" type="password" autocomplete="off" />
                </div>

                <div class="${properties.kcFormGroupClass!} ${properties.kcFormSettingClass!}">
                    <div id="kc-form-options">
                        <#if realm.rememberMe && !usernameEditDisabled??>
                            <div class="checkbox">
                                <label>
                                    <#if login.rememberMe??>
                                        <input tabindex="3" id="rememberMe" name="rememberMe" type="checkbox" checked> ${msg("rememberMe")}
                                    <#else>
                                        <input tabindex="3" id="rememberMe" name="rememberMe" type="checkbox"> ${msg("rememberMe")}
                                    </#if>
                                </label>
                            </div>
                        </#if>
                        </div>
                        <div class="${properties.kcFormOptionsWrapperClass!}">
                            <#if realm.resetPasswordAllowed>
                                <span><a tabindex="5" href="${url.loginResetCredentialsUrl}">${msg("doForgotPassword")}</a></span>
                            </#if>
                        </div>

                  </div>

                  <div id="kc-form-buttons" class="${properties.kcFormGroupClass!}">
                      <input type="hidden" id="id-hidden-input" name="credentialId" <#if auth.selectedCredential?has_content>value="${auth.selectedCredential}"</#if>/>
                      <input tabindex="4" class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}" name="login" id="kc-login" type="submit" value="${msg("doLogIn")}"/>
                  </div>
            </form>
        </#if>
        </div>
        <#if realm.password && social.providers??>
            <div id="kc-social-providers" class="${properties.kcFormSocialAccountContentClass!} ${properties.kcFormSocialAccountClass!}">
                <ul class="${properties.kcFormSocialAccountListClass!} <#if social.providers?size gt 4>${properties.kcFormSocialAccountDoubleListClass!}</#if>">
                    <#list social.providers as p>
                        <li class="${properties.kcFormSocialAccountListLinkClass!}"><a href="${p.loginUrl}" id="zocial-${p.alias}" class="zocial ${p.providerId}"> <span>${p.displayName}</span></a></li>
                    </#list>
                </ul>
            </div>
        </#if>
      </div>
    <#elseif section = "info" >
        <#if realm.password && realm.registrationAllowed && !usernameEditDisabled??>
            <div id="kc-registration">
                <span>${msg("noAccount")} <a tabindex="6" href="${url.registrationUrl}">${msg("doRegister")}</a></span>
            </div>
        </#if>
    </#if>

</@layout.registrationLayout>
问题回答

Keycloak s Server Developer guide recommends that when you create a theme you start by extending an existing theme.

So I created a project directory for my new theme:

mkdir serendipity-keycloak-theme

Launched the Keycloak Docker image:

cd serendipity-keycloak-theme

docker run -d --name keycloak 
  -p 10001:8080 
  -v ~/workspace/Robinyo/serendipity-keycloak-theme:/serendipity-keycloak-theme 
  -e KEYCLOAK_USER=admin 
  -e KEYCLOAK_PASSWORD=secret 
  jboss/keycloak:9.0.2

And then I copied the default Keycloak theme:

docker cp keycloak:/opt/jboss/keycloak/themes/keycloak ./theme

For example:

├── /serendipity-keycloak-theme
     └── /theme
           └── /account
           └── /admin
           └── /common
           └── /email
           └── /login
                 └── /resources
                       └── /css
                       └── /img
                 ├── theme.properties
           └── /welcome

Keycloak s Server Developer guide also recommends that while your creating a theme you should disable caching so that you can preview your changes as you make them.

So I copied the Keycloak Docker image s standalone-ha.xml:

docker cp keycloak:/opt/jboss/keycloak/standalone/configuration/standalone-ha.xml .

And updated it as follows:

<theme>
  <staticMaxAge>-1</staticMaxAge>
  <cacheThemes>false</cacheThemes>
  <cacheTemplates>false</cacheTemplates>
  
  ...
  
</theme>

Keycloak uses templates written in the FreeMarker Template Language (FTL) to generate HTML.

Keycloak s Server Developer guide recommends that when you create a custom template, that you copy the template from the base theme to your own theme, then apply the modifications you need.

For example:

├── /serendipity-keycloak-theme
     └── /theme
           └── /account
           └── /admin
           └── /email
           └── /login
                 └── /messages
                 └── /resources
                       └── /css
                       └── /img
                       └── /js
                 ├── login.ftl
                 ├── template.ftl
                 ├── theme.properties
           └── /welcome

I copied the category template (template.ftl) and the Login template (login.ftl) from the base theme and updated them to use MDC Web components, for example:

<#-- login.ftl  -->

...

<div class="${properties.kcFormGroupClass!}">

    <div class="mdc-text-field mdc-text-field--with-leading-icon ${properties.kcLabelClass!} <#if usernameEditDisabled??>mdc-text-field--disabled</#if>">
        <i class="material-icons mdc-text-field__icon" role="button">person</i>
        <input tabindex="0" required id="username" class="mdc-text-field__input ${properties.kcInputClass!}" name="username" value="${(login.username!  )}" type="text" autofocus autocomplete="off" <#if usernameEditDisabled??>disabled</#if>>
        <div class="mdc-line-ripple"></div>
        <label for="username" class="mdc-floating-label ${properties.kcLabelClass!}">
            <#if !realm.loginWithEmailAllowed>
                ${msg("username")}
            <#elseif !realm.registrationEmailAsUsername>
                ${msg("usernameOrEmail")}
            <#else>
                ${msg("email")}
            </#if>
        </label>
    </div>

</div>

...

The Login page:

enter image description here

I wrote two blog articles which you can see here:





相关问题
凌驾于多租期的钥匙花 the?

so I have micro service application where one of those called auth_manager used to authenticate and register new user , I use the auth_manager to get token for user from keycloak , and other services ...

Add custom attribute in my keycloak client roles

I can add a custom attribute to my user following this link. I want to add a (common) custom attribute to my client roles. Is it possible? I tried to replicate the custom attribute like my user ...

Keycloak custom theme reject login.ftl

I create custom keycloak login screen. I download from keycloak web page Server Standalone server distribution And copy from keycloak-8.0.2 hemeskeycloak to C:xxconfigurationkeycloak...

WSO2 APIM 4.2 http gateaway mixed content error

I m using wso2 apim 4.2 with keycloak key manager to invoke an api through http. I published the api to get published through http and https, for the domain I already inject the ssl on wso2 apim. I ...

热门标签