CAS单点登录-自定义主题、界面 (十一)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010475041/article/details/78201261

CAS单点登录-自定义主题、界面 (十一)

在集成了sso之后,cas的登录界面一般都不满足上线要求,所以必须来一套自定义登录界面,当然了甚至会提出登录界面里面新增部门选择呀、区域选择等等这些业务性的

当然了我们还有以下的使用场景:

  • 不同接入端登录页不一
  • 默认主题

本章目标

  1. 图标改变
  2. 背景颜色改变
  3. 部分字体改变

疑问与介绍

官方文档:https://apereo.github.io/cas/5.1.x/installation/User-Interface-Customization.html

主题?

先介绍下什么叫主题,主题就意味着风格不一,目的就是为了在不同的接入端(service)展示不同的页面,就例如淘宝登录天猫登录,其中登录点还是一个sso,但淘宝登录卖的广告是淘宝的,而天猫登录卖的广告是天猫的


简略看完后,会有以下的规范:

  • 静态资源(js,css)存放目录为src/main/resources/static
  • html资源存(thymeleaf)放目录为src/main/resources/templates
  • 主题配置文件存放在src/main/resources并且命名为[theme_name].properties
  • 主题页面html存放目录为src/main/resources/templates/<theme-id>

可能看完上面的规范会有一些疑问

主题渲染是怎么样的?

官方文档明确说明,登录页渲染文件为casLoginView.html,那意味我们在主题具体目录下新增改文件并且按照cas要求写那就可以了

Created with Raphaël 2.1.0 访问cas 有service? 获取service主题 加载主题配置 加载主题登录页 渲染 获取默认主题 yes no

最终目的还是获取到对应的配置文件,渲染对应主题的登录页

接入服务如何指定主题?

{
  "@class" : "org.apereo.cas.services.RegexRegisteredService",
  "serviceId" : "^https://www.example.org",
  "name" : "MyTheme",
  "theme" : "[theme_name]",
  "id" : 1000
}

theme为key指定配置文件id

若主题配置文件为test_theme.application"theme":"test_theme"

如何修改默认主题?

application.properties

cas.theme.defaultThemeName=[theme_id]

实战

新建主题配置文件

在src/main下新建demo.properties

demo.css.file=/themes/demo/css/demo.css

新建样式文件

由于上面指定了样式文件位置,我们必须在,src\main\resources\static\themes\demo\css下建立demo.css

为了简单起见,h1标签的全为蓝色

h1 {
    color: blue;
}

新建登录也文件

明码规定文件名为casLoginView.html,路径为src/main/resources/templates/demo

为了简单起见,以最简单的方式展示出来

注意要点:

from表单的内容需要遵循一定的标准th:object等等

<!DOCTYPE html>
<!--
  ~ 版权所有.(c)2008-2017.卡尔科技工作室
  -->
<html>
<head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <title th:text="${#themes.code('demo.pageTitle')}"></title>
    <link rel="stylesheet" th:href="@{${#themes.code('demo.css.file')}}"/>
</head>

<body>
<h1 th:text="${#themes.code('demo.pageTitle')}"></h1>
<div>
    <form method="post" th:object="${credential}">
        <div th:if="${#fields.hasErrors('*')}">
            <span th:each="err : ${#fields.errors('*')}" th:utext="${err}"/>
        </div>
        <h2 th:utext="#{screen.welcome.instructions}"></h2>

        <section class="row">
            <label for="username" th:utext="#{screen.welcome.label.netid}"/>
            <div th:unless="${openIdLocalId}">
                <input class="required"
                       id="username"
                       size="25"
                       tabindex="1"
                       type="text"
                       th:disabled="${guaEnabled}"
                       th:field="*{username}"
                       th:accesskey="#{screen.welcome.label.netid.accesskey}"
                       autocomplete="off"/>
            </div>
        </section>

        <section class="row">
            <label for="password" th:utext="#{screen.welcome.label.password}"/>
            <div>
                <input class="required"
                       type="password"
                       id="password"
                       size="25"
                       tabindex="2"
                       th:accesskey="#{screen.welcome.label.password.accesskey}"
                       th:field="*{password}"
                       autocomplete="off"/>
            </div>
        </section>

        <section>
            <input type="hidden" name="execution" th:value="${flowExecutionKey}"/>
            <input type="hidden" name="_eventId" value="submit"/>
            <input type="hidden" name="geolocation"/>
            <input class="btn btn-submit btn-block"
                   name="submit"
                   accesskey="l"
                   th:value="#{screen.welcome.button.login}"
                   tabindex="6"
                   type="submit"/>
        </section>
    </form>
</div>
</body>
</html>

修改service主题

{
  "@class": "org.apereo.cas.services.RegexRegisteredService",
  "serviceId": "^http://(localhost|192.168).*",
  "name": "Local Services",
  "id": 10000002,
  "description": "this is a localhost service",
  "evaluationOrder": 10000000,
  "theme":"demo"
}

重点为: "theme":"demo"

最终效果如下

这里写图片描述


这里写图片描述


bug和疑问

  1. cas版本5.1.0~5.1.5不支持默认主题目录(application.properties配置了cas.theme.defaultThemeName不会加载主题目录下src/main/resources/templates/[theme_id]/casLoginView.html文件,解决办法为覆盖方式)
  2. 由于访问第一次的时候默认会对页面进行缓存,需要spring.thymeleaf.cache=false
  3. 当访问cas携带service,主题目录生效
  4. 上述问题在cas5.2.x得到 解决

加载代码如下:
发现,如果没有service(39~52行代码)是不会到主题目录下加载主题页面

public class RegisteredServiceThemeBasedViewResolver extends ThymeleafViewResolver {

    private static final Logger LOGGER = LoggerFactory.getLogger(RegisteredServiceThemeBasedViewResolver.class);

    private final ServicesManager servicesManager;
    private final ArgumentExtractor argumentExtractor;
    private final String prefix;
    private final String suffix;

    public RegisteredServiceThemeBasedViewResolver(final ServicesManager servicesManager,
                                                   final ArgumentExtractor argumentExtractor,
                                                   final String prefix,
                                                   final String suffix) {
        this.servicesManager = servicesManager;
        this.argumentExtractor = argumentExtractor;
        this.prefix = prefix;
        this.suffix = suffix;
    }

    @Override
    protected View loadView(final String viewName, final Locale locale) throws Exception {
        final View view = super.loadView(viewName, locale);

        final RequestContext requestContext = RequestContextHolder.getRequestContext();
        final WebApplicationService service;

        final HttpServletResponse response;
        final List<ArgumentExtractor> argumentExtractorList = Collections.singletonList(this.argumentExtractor);

        if (requestContext != null) {
            response = WebUtils.getHttpServletResponse(requestContext);
            service = WebUtils.getService(argumentExtractorList, requestContext);
        } else {
            final HttpServletRequest request = WebUtils.getHttpServletRequestFromRequestAttributes();
            service = WebUtils.getService(argumentExtractorList, request);
            response = WebUtils.getHttpServletResponseFromRequestAttributes();
        }

        if (service == null) {
            return view;
        }

        final RegisteredService registeredService = this.servicesManager.findServiceBy(service);
        if (registeredService != null) {
            try {
                RegisteredServiceAccessStrategyUtils.ensureServiceAccessIsAllowed(service, registeredService);
            } catch (final Exception e) {
                response.setStatus(HttpStatus.UNAUTHORIZED.value());
            }
        }

        if (registeredService != null && StringUtils.hasText(registeredService.getTheme()) && view instanceof AbstractThymeleafView) {
            LOGGER.debug("Attempting to locate views for service [{}] with theme [{}]",
                    registeredService.getServiceId(), registeredService.getTheme());

            final AbstractThymeleafView thymeleafView = (AbstractThymeleafView) view;
            final String viewUrl = registeredService.getTheme() + '/' + thymeleafView.getTemplateName();

            final String viewLocationUrl = prefix.concat(viewUrl).concat(suffix);
            LOGGER.debug("Attempting to locate view at [{}]", viewLocationUrl);
            final TemplateLocation location = new TemplateLocation(viewLocationUrl);
            if (location.exists(getApplicationContext())) {
                LOGGER.debug("Found view [{}]", viewUrl);
                thymeleafView.setTemplateName(viewUrl);
            } else {
                LOGGER.debug("View [{}] does not exist. Falling back to default view at [{}]", viewLocationUrl, thymeleafView.getTemplateName());
            }
        }
        return view;
    }
}

下载代码尝试:GitHub 其他版本可以到GitHub或者码云查看

发现一些意外的事情可以考虑翻翻前面的博客进行学习哦

作者联系方式

如果技术的交流或者疑问可以联系或者提出issue。

邮箱:[email protected]

QQ: 756884434 (请注明:SSO-CSDN)

猜你喜欢

转载自blog.csdn.net/u010475041/article/details/78201261