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/
可能看完上面的规范会有一些疑问
主题渲染是怎么样的?
官方文档明确说明,登录页渲染文件为 casLoginView.html,那意味我们在主题具体目录下新增改文件并且按照 cas 要求写那就可以了
访问 cas
有 service?
获取 service 主题
加载主题配置
加载主题登录页
渲染
获取默认主题
yes
no
最终目的还是获取到对应的配置文件,渲染对应主题的登录页
接入服务如何指定主题?
{
“@class” : “org.apereo.cas.services.RegexRegisteredService”,
“serviceId” : “^https://www.example.org”,
“name” : “MyTheme”,
“theme” : “[theme_name]”,
“id” : 1000
}
1
2
3
4
5
6
7
theme 为 key 指定配置文件 id
若主题配置文件为 test_theme.application 则”theme”:”test_theme”
如何修改默认主题?
application.properties
cas.theme.defaultThemeName=[theme_id]
1
实战
新建主题配置文件
在 src/main 下新建 demo.properties
demo.css.file=/themes/demo/css/demo.css
1
新建样式文件
由于上面指定了样式文件位置,我们必须在,src\main\resources\static\themes\demo\css 下建立 demo.css
为了简单起见,h1 标签的全为蓝色
h1 {
color: blue;
}
1
2
3
新建登录也文件
明码规定文件名为 casLoginView.html,路径为 src/main/resources/templates/demo
为了简单起见,以最简单的方式展示出来
注意要点:
from 表单的内容需要遵循一定的标准 th:object 等等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
修改 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”
}
1
2
3
4
5
6
7
8
9
重点为: “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,主题目录生效
上述问题在 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;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
下载代码尝试: 其他版本可以到 GitHub 或者码云查看
发现一些意外的事情可以考虑翻翻前面的博客进行学习哦
作者:悟空 _
来源:CSDN
原文:https://blog.csdn.net/u010475041/article/details/78201261
版权声明:本文为博主原创文章,转载请附上博文链接!