总结
CAS对提供单点登录的服务采用双向控制。第一,cas client端需要指定提供服务的casServer;第二,casClient提供服务service,需要在casServer中进行注册。
开篇概念
- 服务:指的是cas允许接入的客户端的地址,cas在数据库中进行相应的地址进行了持久化。不在服务之列的客户端地址,将被限制由cas提供的服务。
服务管理表
基于数据源的cas的集成,会侵入数据库并初始化一些表,其中管理服务的表为:REGISTEREDSERVICEIMPL
通配规则
expression_type
列记录了,cas服务匹配支持的2种通配规则:
- 正则(
regex
) - 类正则(
ant
)——cas默认提供的通配规则。
cas的service通配校验对应的实现类为:RegexRegisteredService
、RegisteredServiceImpl
。
/**
* Mutable registered service that uses Ant path patterns for service matching.
*
* @author Scott Battaglia
* @author Marvin S. Addison
* @since 3.1
*/
@Entity
@DiscriminatorValue("ant")
public class RegisteredServiceImpl extends AbstractRegisteredService {
/** Unique Id for serialization. */
private static final long serialVersionUID = -5906102762271197627L;
private static final PathMatcher PATH_MATCHER = new AntPathMatcher();
public void setServiceId(final String id) {
this.serviceId = id;
}
public boolean matches(final Service service) {
return service != null && PATH_MATCHER.match(serviceId.toLowerCase(), service.getId().toLowerCase());
}
protected AbstractRegisteredService newInstance() {
return new RegisteredServiceImpl();
}
}
ant匹配相关实现代码实际上用到的是Spring-core包下的org.springframework.util.AntPathMatcher
。
ant通配规则
通配符 说明
? 匹配任何单字符
* 匹配0或者任意数量的字符
** 匹配0或者更多的目录
代码验证
public class AntPathMatcherTest {
private static final PathMatcher PATH_MATCHER = new AntPathMatcher();
@Test
public void testMatch(){
//?表示占位符需要1位
System.out.println(PATH_MATCHER.match("http://172.18.10?.*/*/**","http://172.18.10.160:26955/bbs")); //false
System.out.println(PATH_MATCHER.match("http://172.18.10?.*/*/**","http://172.18.103.160:26955/bbs")); //true
System.out.println(PATH_MATCHER.match("http://172.18.103.*/*/**","http://172.18.103.160:26955/bbs")); //true
}
}
补充阅读:ANT通配——https://www.cnblogs.com/cyjch/archive/2012/03/28/2421353.html
服务加载
DefaultServicesManagerImpl.java
实现ServiceManager
接口:
- 用来加载数据库中的服务配置信息,项目启动的时候就会获取完成,配置信息存储在内存中;
- 借助quartz任务自动进行更新——从数据库重新读取。private void load() 查询数据库获取授权service信息;
cas-sevlet.xml
:
<!-- 服务加载定时任务 -->
<bean id="serviceRegistryReloaderJobDetail"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"
p:targetObject-ref="servicesManager"
p:targetMethod="reload"/>
<!-- 服务加载定时任务:默认延时2分钟 -->
<bean id="periodicServiceRegistryReloaderTrigger"
class="org.springframework.scheduling.quartz.SimpleTriggerBean"
p:jobDetail-ref="serviceRegistryReloaderJobDetail"
p:startDelay="${service.registry.quartz.reloader.startDelay:120000}" p:repeatInterval="${service.registry.quartz.reloader.repeatInterval:120000}"/>
ApplicationContext.xml
:
<bean id="servicesManager" class="org.jasig.cas.services.DefaultServicesManagerImpl"
c:serviceRegistryDao-ref="serviceRegistryDao" />
日志信息:
2019-04-30 17:29:54,792 DEBUG [org.quartz.core.JobRunShell] - <Calling execute on job DEFAULT.serviceRegistryReloaderJobDetail>
2019-04-30 17:29:54,792 INFO [org.jasig.cas.services.DefaultServicesManagerImpl] - <Reloading registered services.>
授权服务检查
ServiceAuthorizationCheck.java
进行授权的检验;检查不通过时报错如下:
测试环节
service配置距离说明:
1、允许访问百度;
2、不允许访问新浪。
http://localhost:24588/cas/login?service=http://www.sina.com
查看日志:
2020-06-02 14:45:27,713 WARN [org.jasig.cas.CentralAuthenticationServiceImpl] - <ServiceManagement: Service [http://www.sina.com] is not allowed to use SSO.>
实现原理
<!-- CentralAuthenticationService -->
<bean id="centralAuthenticationService" class="org.jasig.cas.CentralAuthenticationServiceImpl">
<constructor-arg index="0" ref="ticketRegistry"/>
<constructor-arg index="1">
<null />
</constructor-arg>
<constructor-arg index="2" ref="authenticationManager"/>
<constructor-arg index="3" ref="ticketGrantingTicketUniqueIdGenerator"/>
<constructor-arg index="4" ref="uniqueIdGeneratorsMap"/>
<constructor-arg index="5" ref="grantingTicketExpirationPolicy"/>
<constructor-arg index="6" ref="serviceTicketExpirationPolicy"/>
<!-- 服务管理器注入 -->
<constructor-arg index="7" ref="servicesManager"/>
<constructor-arg index="8" ref="logoutManager"/>
<property name="persistentIdGenerator" ref="persistentIdGenerator"/>
</bean>