CAS单点登录-自定义主题、界面 (十一)
来源:互联网 发布:js match对象 编辑:程序博客网 时间:2024/06/05 17:20
CAS单点登录-自定义主题、界面 (十一)
在集成了sso之后,cas的登录界面一般都不满足上线要求,所以必须来一套自定义登录界面,当然了甚至会提出登录界面里面新增部门选择呀、区域选择等等这些业务性的
当然了我们还有以下的使用场景:
- 不同接入端登录页不一
- 默认主题
本章目标
- 图标改变
- 背景颜色改变
- 部分字体改变
疑问与介绍
官方文档: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要求写那就可以了
最终目的还是获取到对应的配置文件,渲染对应主题的登录页
接入服务如何指定主题?
{ "@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和疑问
- cas版本
5.1.0~5.1.5
不支持默认主题目录(application.properties配置了cas.theme.defaultThemeName
不会加载主题目录下src/main/resources/templates/[theme_id]/casLoginView.html
文件,解决办法为覆盖方式) - 由于访问第一次的时候默认会对页面进行缓存,需要
spring.thymeleaf.cache=false
- 当访问cas携带service,主题目录生效
- 上述问题在cas
5.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或者码云查看
发现一些意外的事情可以考虑翻翻前面的博客进行学习哦
作者联系方式
如果技术的交流或者疑问可以联系或者提出issue。
邮箱:huang.wenbin@foxmail.com
QQ: 756884434 (请注明:SSO-CSDN)
- CAS单点登录-自定义主题、界面 (十一)
- 改造CAS单点登录 --- 自定义登陆页面(客户端)
- 改造CAS单点登录 --- 自定义登陆页面(服务端)
- CAS单点登录-自定义认证之JDBC(五)
- CAS单点登录-自定义认证之Shiro、Rest(六)
- CAS单点登录-自定义认证之重写Credential(十五)
- sso 单点登录cas使用(3): cas 4.2.7 服务端自定义登录样式
- CAS单点登录-Cas-Management(八)
- CAS单点登录(三)--服务端改造(登录页及登录方式的自定义)
- 单点登录cas常见问题(十一) - 怎么搭建oauth服务器?
- CAS单点登录-登录校验码(十七)
- CAS单点登录-单用户登录(十九)
- SSO单点登录系列4:cas-server登录页面自定义修改过程(jsp页面修改)
- 基于CAS实现单点登录(SSO):自定义登录验证方法
- 基于CAS实现单点登录(SSO):自定义登录验证方法
- 单点登录CAS使用记(三):实现自定义验证用户登录
- CAS框架单点登录,自定义验证登录方式(添加系统标识)
- CAS单点登录自定义登录页面错误提示
- 在linux环境下安装tensorflow
- PL/SQL之--存储过程
- LeakCanary原理解析
- js 弹出确认 取消对话框
- git 新建库流程和上传
- CAS单点登录-自定义主题、界面 (十一)
- java中implements和extends
- css复习——表格与表单
- Linux有问必答:如何检查Linux的内存使用状况
- 目录处理命令rm
- 配置Jstl的Maven依赖
- linux下利用gcc编译C和C++
- 关于自定义控件的onMeasure()其中的MeasureSpec
- 第四周项目一