在企业级应用开发中,随着系统数量的不断增加,用户需要频繁登录不同系统,这不仅降低了工作效率,也增加了管理成本。单点登录(Single Sign-On,SSO)技术应运而生,而中央认证服务(CAS,Central Authentication Service)作为一种成熟的开源单点登录解决方案,在 Java 生态中得到广泛应用。本文将深入探讨 Spring Boot 基于 CAS 实现单点登录的原理、实现方式、优缺点以及优化策略,并通过具体代码示例帮助读者快速掌握这一技术。
CAS 系统主要由两部分组成:CAS Server和CAS Client。
创建一个 Spring Boot 项目,在pom.xml
文件中添加以下依赖:
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-securityartifactId>
dependency>
<dependency>
<groupId>org.jasig.cas.clientgroupId>
<artifactId>cas-client-coreartifactId>
<version>3.6.2version>
dependency>
dependencies>
在application.yml
文件中配置 CAS Server 的地址和应用系统的相关信息:
cas:
server-url-prefix: https://cas.example.com # CAS Server地址
client-host-url: https://app1.example.com # 应用系统地址
login-path: /login # CAS Server登录路径
logout-path: /logout # CAS Server登出路径
创建SecurityConfig
类,配置 CAS 认证相关的过滤器:
import org.jasig.cas.client.authentication.AuthenticationFilter;
import org.jasig.cas.client.session.SingleSignOutFilter;
import org.jasig.cas.client.session.SingleSignOutHttpSessionListener;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.web.filter.DelegatingFilterProxy;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Value("${cas.server-url-prefix}")
private String casServerUrlPrefix;
@Value("${cas.client-host-url}")
private String casClientHostUrl;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/", "/public/**").permitAll()
.anyRequest().authenticated()
.and()
.logout()
.logoutUrl(casServerUrlPrefix + "/logout")
.logoutSuccessUrl(casClientHostUrl);
}
@Bean
public FilterRegistrationBean<DelegatingFilterProxy> casAuthenticationFilter() {
FilterRegistrationBean<DelegatingFilterProxy> registration = new FilterRegistrationBean<>();
DelegatingFilterProxy filter = new DelegatingFilterProxy("authenticationFilter");
filter.setTargetFilterLifecycle(true);
registration.setFilter(filter);
registration.addUrlPatterns("/*");
return registration;
}
@Bean
public AuthenticationFilter authenticationFilter() {
AuthenticationFilter authenticationFilter = new AuthenticationFilter();
authenticationFilter.setCasServerLoginUrl(casServerUrlPrefix + "/login");
authenticationFilter.setServerName(casClientHostUrl);
return authenticationFilter;
}
@Bean
public FilterRegistrationBean<SingleSignOutFilter> singleSignOutFilter() {
FilterRegistrationBean<SingleSignOutFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new SingleSignOutFilter());
registration.addUrlPatterns("/*");
return registration;
}
@Bean
public ServletListenerRegistrationBean<SingleSignOutHttpSessionListener> singleSignOutHttpSessionListener() {
ServletListenerRegistrationBean<SingleSignOutHttpSessionListener> registration = new ServletListenerRegistrationBean<>();
registration.setListener(new SingleSignOutHttpSessionListener());
return registration;
}
}
上述配置中,AuthenticationFilter
用于拦截未认证的请求并将用户重定向到 CAS Server 进行登录;SingleSignOutFilter
和SingleSignOutHttpSessionListener
用于实现单点登出功能,当用户在 CAS Server 登出时,自动注销所有应用系统的会话。
创建一个简单的控制器,模拟受保护资源:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ProtectedResourceController {
@GetMapping("/protected")
public String protectedResource() {
return "This is a protected resource accessed via CAS SSO.";
}
}
将 CAS Server 进行集群部署,通过负载均衡器(如 Nginx、Apache)将请求分发到不同的 CAS Server 节点,提高系统的可用性和性能。同时,集群部署还可以实现会话共享,确保用户在不同节点间切换时无需重新登录。
通过 Nginx 负载均衡实现 CAS Server 集群,提升系统可用性。配置 Nginx 反向代理:
upstream cas_servers {
server cas1.example.com:8443;
server cas2.example.com:8443;
}
server {
listen 443 ssl;
server_name cas.example.com;
ssl_certificate /path/to/cas.crt;
ssl_certificate_key /path/to/cas.key;
location / {
proxy_pass https://cas_servers;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
引入缓存机制(如 Redis、Ehcache)对 Service Ticket 和 Ticket Granting Ticket 进行缓存,减少对数据库或文件系统的访问,提高票据验证的效率。在 Spring Boot 中,可以使用@Cacheable注解方便地实现缓存功能。
引入 Redis 缓存 Service Ticket,减少数据库或文件系统的 I/O 操作。使用 Spring Cache 集成 Redis:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableCaching
public class CacheConfig {
// 配置Redis缓存管理器等相关bean
}
在票据验证逻辑中添加缓存注解:
import org.springframework.cache.annotation.Cacheable;
@Cacheable("serviceTickets")
public boolean validateServiceTicket(String serviceTicket) {
// 实际验证逻辑
}
通过本文的介绍,我们详细了解了 Spring Boot 基于 CAS 实现单点登录的原理、实现方式、优缺点以及优化策略,并通过具体代码示例进行了实践。CAS 作为一种成熟的单点登录解决方案,能够有效解决企业多系统间的统一认证问题。在实际应用中,需要根据项目需求和特点,合理配置和优化 CAS 系统,以实现安全、高效、用户友好的单点登录功能。