之前一篇介绍了cas认证服务的整个流程;这篇文章Springboot框架里面如何整合cas实现整个认证的流程;
1>首先引入Springsecurity cas的依赖jar
compile "org.springframework.security:spring-security-cas"
2>配置CasSecurityConfig类
@Configuration
public class CasSecurityConfig {
@Value("${cas.server.url}")
private String casServerUrl;
@Value("${cas.service.home}")
private String serverHome;
@Value("${cas.service.backEndService}")
private String backEndService;
@Value("${cas.server.prefix}")
private String casServerUrlPrefix;
@Autowired
private CustomCasUserDetailsService customCasUserDetailsService;
@Bean
public ServiceProperties serviceProperties() {
ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.setService(backEndService + "/login/cas");
serviceProperties.setSendRenew(false);
return serviceProperties;
}
@Bean
@Primary
public AuthenticationEntryPoint authenticationEntryPoint(
ServiceProperties sP) {
CasAuthenticationEntryPoint entryPoint = new CasAuthenticationEntryPoint();
//cas登录服务
entryPoint.setLoginUrl(casServerUrl + "/cas/login");
entryPoint.setServiceProperties(sP);
return entryPoint;
}
@Bean
public TicketValidator ticketValidator() {
return cas30ProxyTicketValidator();
}
TicketValidator cas30ProxyTicketValidator() {
// 是否开启代理
Cas30ProxyTicketValidator cas30ProxyTicketValidator = new Cas30ProxyTicketValidator(casServerUrlPrefix);
cas30ProxyTicketValidator.setProxyGrantingTicketStorage(new ProxyGrantingTicketStorageImpl());
cas30ProxyTicketValidator.setAcceptAnyProxy(true);
cas30ProxyTicketValidator.setURLConnectionFactory(new SophonHttpsURLConnectionFactory());
return cas30ProxyTicketValidator;
}
@Bean
public CasAuthenticationProvider casAuthenticationProvider() {
CasAuthenticationProvider provider = new CasAuthenticationProvider();
provider.setServiceProperties(serviceProperties());
provider.setTicketValidator(ticketValidator());
provider.setAuthenticationUserDetailsService(customCasUserDetailsService);
provider.setKey("an_id_for_this_auth_provider_only");
return provider;
}
@Bean
public SecurityContextLogoutHandler securityContextLogoutHandler() {
return new SecurityContextLogoutHandler();
}
@Bean
public LogoutFilter logoutFilter() {
//退出后转发路径
LogoutFilter logoutFilter = new LogoutFilter(
casServerUrl + "/cas/logout?service=" + serverHome,
securityContextLogoutHandler());
logoutFilter.setLogoutRequestMatcher(new AntPathRequestMatcher("/api/logout"));
return logoutFilter;
}
@Bean
public SingleSignOutFilter singleSignOutFilter() {
//单点退出
SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
singleSignOutFilter.setCasServerUrlPrefix(casServerUrlPrefix);
singleSignOutFilter.setIgnoreInitConfiguration(true);
return singleSignOutFilter;
}
//设置退出监听
@EventListener
public SingleSignOutHttpSessionListener singleSignOutHttpSessionListener(
HttpSessionEvent event) {
return new SingleSignOutHttpSessionListener();
}
}
1)ServiceProperties配置了认证成功之后跳转的地址,cas在认证成功之后返回这个地址,并携带ticket;所以注意这个地址在springSecurity中一定是permitAll;不然会出现死循环;这里默认就使用这个地址"/login/cas",不然会有问题,后面会详细说;
2)AuthenticationEntryPoint配置了cas认证服务器的地址;
3)TicketValidator配置了校验ticket的类,应用接收到ticket之后,会通过这个类向cas认证服务器发送校验的请求校验ticket的有效性;
4)CasAuthenticationProvider 包含了校验ticket的配置以及校验成功之后获取用户信息的配置;这里配置的是CustomCasUserDetailsService
5)casServerUrlPrefix是cas的前缀地址,比如https://gg-sophon-13:8393/cas;
3>添加配置
在SecurityConfiguration中添加cas的过滤器,如图所示
同时添加如下配置bean
@Override
protected AuthenticationManager authenticationManager(){
//设置cas认证提供
return new ProviderManager(
Arrays.asList(authenticationProvider));
}
@Bean
public CasAuthenticationFilter casAuthenticationFilter(ServiceProperties sp) {
//cas认证过滤器,当触发本filter时,对ticket进行认证
CasAuthenticationFilter filter = new CasAuthenticationFilter();
filter.setServiceProperties(sp);
filter.setAuthenticationManager(authenticationManager());
filter.setAuthenticationSuccessHandler(new CasAuthenticationSuccessHandler());
return filter;
}
整个配置到这里基本就结束了,下面跟踪下源码,解释下自己的两个疑问:
1.为什么serviceProperties.setService的地址后缀要是"/login/cas"?我改成其他的行不行,比如"/login/cas123"
2.具体校验ticket的逻辑是怎么处理的;
4>疑问解释
1)我把地址改成了"/login/cas123"
结果如图所示
那么为什么地址是"/login/cas"的时候就可以成功解析到ticket,然后去处理,改成"/login/cas123"就不行了那?带着疑问我断点调试了源代码发现
这里的返回值是ture,所以不需要认证,然后又没有一个接口或者页面对应就404了;跟踪进去这里的requiresAuthentication所做的操作
这里的match匹配的url是"/login/cas",而我们的request的地址是"/login/cas123",当然不匹配了;那么这个match中的地址是在哪里设置的那,我们看下AbstractAuthenticationProcessingFilter的子类CasAuthenticationFilter
在构造的时候默认这个地址就是"/login/cas";第一个问题解决了
2)第二个疑问,ticket拿到之后怎么处理的,这个是封装的,但是还是想看一下具体的逻辑;
跟踪到父类具体逻辑应该在这里
AbstractUrlBasedTicketValidator这个类里面
构造个ticket的url,根据cas的协议去校验,这个url地址是
p3/proxyValidate 是api地址,应该是根据不同的cas协议,这个地址也是固定的,后面追加上ticket以及service地址;
验证完ticket之后,cas认证服务器返回用户的信息,以map的方式进行村粗;如图所示
然后调用我们之前定义的CustomCasUserDetailsService类loadUserDetails方法解析用户信息,之后存储在session中;