- pandaAnthony:spring boot cas 服务端
- pandaAnthony:spring boot cas 服务端
- pandaAnthony:spring boot cas 服务端
- 第2讲 Kotlin + Spring Boot 集成 JPA
- 《 Kotlin + Spring Boot : K2EE 服
- 第1讲 Spring Boot 快速开始 《Kotlin + S
- 【Kotlin Spring Boot 服务端开发: 问题集锦】
- 《 Kotlin + Spring Boot : 下一代 Jav
- 【Kotlin Spring Boot 服务端开发: 问题集锦】
- SpringBoot整合SpringBootAdmin监控
这个系列有3篇文章:
- spring boot cas 服务端和spring security客户端搭建(一):主要介绍怎么用spring boot cas搭建https的服务端
- spring boot cas 服务端和spring security客户端搭建(二):主要介绍怎么用怎么结合数据库用cas提供的动态加密方式登录及相关配置
- spring boot cas 服务端和spring security客户端搭建(三):主要介绍怎么结合spring security客户端进行整合及http方式登录配置
终于腾出时间来写完这个系列了。
接着上篇spring boot cas 服务端和spring security客户端搭建(二)继续介绍cas与spring security客户端的整合。官网的资料只在github上找到了客户端的代码https://github.com/apereo/java-cas-client#spring-security-integration,而且还不是spring boot版本的:


由于学习spring boot不久,还要花更多时间研究其他功能,就没花时间去把这些xml配置转成spring boot的配置了;参考https://blog.csdn.net/cl_andywin/article/details/53998986,搭建了基于spring boot的spring security cas客户端。
引入相关的依赖包
在对应工程的pom文件中引入spring-security-cas包(其他相关spring boot 的包就不在这里描述了,这里的包的版本和spring boot parent版本对应)
spring boot版本,项目中用的是2.0.3.RELEASE:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/>
</parent>
spring boot security和 security cas包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-cas</artifactId>
</dependency>
配置文件和配置类
CasProperties,cas服务端和客户端相关的配置信息(这里用到了lombok.Data来生成get,set方法):
@Data
@Component
public class CasProperties {
@Value("${security.cas.server.host}")
private String casServerUrl;
@Value("${security.cas.server.login}")
private String casServerLoginUrl;
@Value("${security.cas.server.logout}")
private String casServerLogoutUrl;
@Value("${security.cas.service.host}")
private String appServerUrl;
@Value("${security.cas.service.login}")
private String appLoginUrl;
@Value("${security.cas.service.logout}")
private String appLogoutUrl;
}
对应的配置信息(这时cas服务用的是http形式的了,因为环境限制不能用域名的,而且http的省事,在文章的后面会介绍怎么使用http),配置的具体含义这里就不描述了:
security:
cas:
server:
host: http://xxx.xxx.xxx.xxx:8443/cas
login: ${security.cas.server.host}/login
logout: ${security.cas.server.host}/logout?service=${security.cas.service.host}
service:
host: http://localhost:8764
login: /login
logout: /logout
WebSecurityConfig配置类,最核心的配置(上面cas相关地址的配置不一定要那样实现,可能有更灵活的办法;下面登出的相关配置没有起到想象的作用,一个应用登出了,其他应用不会一起登出;后续找到办法了会继续补充):
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CasProperties casProperties;
/**
* configure(AuthenticationManagerBuilder): 身份验证配置,用于注入自定义身份验证Bean和密码校验规则
*
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
super.configure(auth);
auth.authenticationProvider(casAuthenticationProvider());
}
/**
* configure(WebSecurity): Web层面的配置,一般用来配置无需安全检查的路径
*
* @param web
* @throws Exception
*/
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/static/**", "/templates/**");
}
/**
* configure(HttpSecurity): Request层面的配置,对应XML Configuration中的<http>元素
*
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()// 配置安全策略
.antMatchers("/login/cas").permitAll()
.and().authorizeRequests().anyRequest().authenticated()
.and().logout().permitAll()// 定义logout不需要验证
.and().formLogin().defaultSuccessUrl("/index"); // 登录成功之后的跳转
http.exceptionHandling().authenticationEntryPoint(casAuthenticationEntryPoint())
.and().addFilter(casAuthenticationFilter())
.addFilterBefore(casLogoutFilter(), LogoutFilter.class)
.addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class);
http.csrf().disable();
// 关闭spring security默认的frame访问限制
http.headers().frameOptions().sameOrigin();
}
@Bean
public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {
CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();
casAuthenticationEntryPoint.setLoginUrl(casProperties.getCasServerLoginUrl());
casAuthenticationEntryPoint.setServiceProperties(serviceProperties());
return casAuthenticationEntryPoint;
}
/**
* 指定service相关信息
*/
@Bean
public ServiceProperties serviceProperties() {
ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.setService(casProperties.getAppServerUrl() + casProperties.getAppLoginUrl());
// serviceProperties.setAuthenticateAllArtifacts(true);
serviceProperties.setSendRenew(false);
return serviceProperties;
}
/**
* CAS认证过滤器
*/
@Bean
public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
casAuthenticationFilter.setAuthenticationManager(authenticationManager());
casAuthenticationFilter.setFilterProcessesUrl(casProperties.getAppLoginUrl());
return casAuthenticationFilter;
}
/**
* cas 认证 Provider
*/
@Bean
public CasAuthenticationProvider casAuthenticationProvider() {
CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
casAuthenticationProvider.setAuthenticationUserDetailsService(customUserDetailsService());
// 这里只是接口类型,实现的接口不一样,都可以的。
casAuthenticationProvider.setServiceProperties(serviceProperties());
// casAuthenticationProvider.setTicketValidator(cas20ServiceTicketValidator());
casAuthenticationProvider.setTicketValidator(cas30ServiceTicketValidator());
casAuthenticationProvider.setKey("casAuthenticationProviderKey");
return casAuthenticationProvider;
}
// 用户自定义的AuthenticationUserDetailsService
@Bean
public AuthenticationUserDetailsService<CasAssertionAuthenticationToken> customUserDetailsService() {
return new CustomUserDetailsService();
}
@Bean
public Cas20ServiceTicketValidator cas20ServiceTicketValidator() {
return new Cas20ServiceTicketValidator(casProperties.getCasServerUrl());
}
@Bean
public Cas30ServiceTicketValidator cas30ServiceTicketValidator() {
return new Cas30ServiceTicketValidator(casProperties.getCasServerUrl());
}
/**
* 单点登出过滤器
*/
@Bean
public SingleSignOutFilter singleSignOutFilter() {
SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
singleSignOutFilter.setCasServerUrlPrefix(casProperties.getCasServerUrl());
singleSignOutFilter.setIgnoreInitConfiguration(true);
return singleSignOutFilter;
}
/**
* 请求单点退出过滤器
*/
@Bean
public LogoutFilter casLogoutFilter() {
LogoutFilter logoutFilter = new LogoutFilter(casProperties.getCasServerLogoutUrl(),
new SecurityContextLogoutHandler());
logoutFilter.setFilterProcessesUrl(casProperties.getAppLogoutUrl());
return logoutFilter;
}
public SingleSignOutHttpSessionListener singleSignOutHttpSessionListener() {
return new SingleSignOutHttpSessionListener();
}
@Bean
public ServletListenerRegistrationBean<EventListener> singleSignOutListenerRegistration() {
ServletListenerRegistrationBean<EventListener> registrationBean = new ServletListenerRegistrationBean<EventListener>();
registrationBean.setListener(new SingleSignOutHttpSessionListener());
registrationBean.setOrder(1);
return registrationBean;
}
@Bean
public ServletListenerRegistrationBean<SingleSignOutHttpSessionListener> singleSignOutHttpSessionListenerBean() {
ServletListenerRegistrationBean<SingleSignOutHttpSessionListener> listenerRegistrationBean = new ServletListenerRegistrationBean<>();
listenerRegistrationBean.setEnabled(true);
listenerRegistrationBean.setListener(singleSignOutHttpSessionListener());
listenerRegistrationBean.setOrder(3);
System.out.println("================================singleListener执行");
return listenerRegistrationBean;
}
}
其中需要自己去实现CustomUserDetailsService的用户认证逻辑:
@Service
public class CustomUserDetailsService //实现AuthenticationUserDetailsService,实现loadUserDetails方法
implements AuthenticationUserDetailsService<CasAssertionAuthenticationToken> {
@Override
public UserDetails loadUserDetails(CasAssertionAuthenticationToken token) throws UsernameNotFoundException {
// 结合具体的逻辑去实现用户认证,并返回继承UserDetails的用户对象;
return XXX;
}
}
其中UserDetails是个接口:

到这里,spring boot下spring security整合cas的客户端基本就构建完成了。
http方式的CAS服务端
在第一篇文章(https://www.jianshu.com/p/0b3375b10860)介绍的cas-overlay-template下的配置文件application.properties中修改:
# 去掉https验证
cas.tgc.secure=false
cas.warn.cookie.secure=false
server.ssl.enabled=false
其中cas.tgc.secure和cas.warn.cookie.secure是新增的,server.ssl.enabled默认的是true:

默认情况下,CAS是只支持https请求的;还有个地方需要修改。因为是spring boot结构,可以直接覆盖原有文件,这里就不在额外的加配置了,直接在serveices文件夹下修改HTTSPandIMAPS-10000001.json:


这个文件可以在打包后的target下找到:

在https的边上多加个‘|http’就可以了:

这样CAS就能支持http方式了。
网友评论