cas客户端接入称之为service,必须经过cas的允许才能进行登录,当然不同的客户端可以做不同的事情,其中包括:
- 自定义主题(各客户端登录页自定义)
- 自定义属性(服务属性(固定)与用户属性(动态))
- 自定义协议
- 自定义登录后跳转方式,跳转路径
- 授权策略(拒绝属性、可登录时间范围限制、等等)
- 拒绝授权模式
持久化策略:
- InMemory XML(通过spring bean进行内存存储)
- JSON(通过json文件存储)
- YAML(通过yml文件存储)
- Mongo(文档数据库持久化)
- JPA(关系型数据库持久化)
- DynameDb
- LDAP
- Cochbase
在sso初步上线时推荐采用json文件存储,后面逐步多服务注入时推荐采用Mongo进行存储,
采用cas-management 通过UI方式进行管理我们的数据,目前阶段,持久化策略必须和cas进行配置一致才能生效。
本章进行service的json配置及介绍,yml文件格式配置,参考文档:
https://apereo.github.io/cas/5.3.x/installation/JSON-Service-Management.html
接下来正式进入Service配置实战篇。
JSON配置
这里我只允许http://localhost开头请求的service才能认证。
在resources/services下新建文件localhost-10000002.json,内容如下:
1 2 3 4 5 6 7 8
| { "@class": "org.apereo.cas.services.RegexRegisteredService", "serviceId": "^(http)://localhost.*", "name": "本地服务", "id": 10000002, "description": "这是一个本地允许的服务,通过localhost访问都允许通过", "evaluationOrder": 1 }
|
注意:json文件名字规则为${name}-${id}.json
, id必须为json文件内容id一致。
json文件解释:
- @class:必须为org.apereo.cas.services.RegisteredService的实现类,
对其他属性进行一个json反射对象,常用的有RegexRegisteredService,匹配策略为id的正则表达式
- serviceId:唯一的服务id
- name: 服务名称,会显示在默认登录页
- id:全局唯一标志
- description:服务描述,会显示在默认登录页
- evaluationOrder: 匹配争取时的执行循序(越小越优先)
- theme:主题,默认是apereo
除了以上说的还有很多配置策略以及节点,具体看官方文档, 配置不同的RegisteredService也会有稍微不一样
启用识别
上面新建了json文件cas还不知道要去识别json,需要打开开关.
1 2 3 4 5 6 7 8 9 10
| cas.serviceRegistry.initFromJson=true
|
所有配置可以参考:
https://apereo.github.io/cas/5.3.x/installation/Configuration-Properties.html
另外还需要在 pom.xml 文件中加入依赖配置
1 2 3 4 5 6
| <dependency> <groupId>org.apereo.cas</groupId> <artifactId>cas-server-support-json-service-registry</artifactId> <version>${cas.version}</version> </dependency>
|
自定义登录界面和主题
主题就意味着风格不一,目的就是为了在不同的接入端(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要求写那就可以了
接入服务指定主题
1 2 3 4 5 6 7 8 9
| { "@class" : "org.apereo.cas.services.RegexRegisteredService", "serviceId" : "^(http|https)://app1.*", "name" : "app1", "id" : 100006, "description": "这是一个app1域名下的服务,通过app1访问都允许通过", "evaluationOrder": 10, "theme" : "app1" }
|
修改默认主题
1
| cas.theme.defaultThemeName=app1
|
配置默认后,将直接指定该主题,比如直接访问cas登录,没有传递service参数时等。
css样式表
app1/css/main.css
设置一个标题为粉色
h3 {
color: pink; /粉色/
}
主题配置文件
app1.properties
1 2 3 4 5 6 7 8 9
| css.file=/themes/app1/css/main.css pageTitle= 这是APP 1 网站
standard.custom.css.file=/css/cas.css admin.custom.css.file=/css/admin.css cas.javascript.file=/js/cas.js
|
登录模版
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
| <!DOCTYPE html> <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('pageTitle')}"></title> <link rel="stylesheet" th:href="@{${#themes.code('css.file')@@" /> </head>
<body> <h3 th:text="${#themes.code('pageTitle')}"></h3> <div> <form method="post" th:object="${credential}"> <div th:if="${#fields.hasErrors('*')}"><span th:each="err : ${#fields.errors('*')}" th:utext="${err}" /> </div> <h4 th:utext="#{screen.welcome.instructions}"></h4> <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" th:value="casuser" /> </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" th:value="Mellon" /> </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>
|