CAS单点登录原理与实践

CAS单点登录原理与实践

CAS(Central Authentication Service)是耶鲁大学开发的SSO协议实现,本文深入剖析CAS协议原理、票据机制、部署配置,以及与企业系统的集成实践。

一、SSO概述与CAS协议

1.1 单点登录概念

用户
应用A
应用B
应用C
SSO认证中心

单点登录(Single Sign-On,SSO)允许用户只需登录一次,即可访问所有相互信任的应用系统。

1.2 CAS协议核心角色

票据
CAS角色
存储
一次性
浏览器
Client 客户端
Browser 浏览器
CAS Server
Service 应用服务
TGT Ticket Granting Ticket
ST Service Ticket
TGC Ticket Granting Cookie

角色 说明
Client/Browser 用户使用的浏览器
CAS Server 认证中心服务器
Service 接入CAS的应用服务
TGT 票据授权票据,存储在Server端
ST 服务票据,一次性使用
TGC 票据授权Cookie,存储在浏览器

1.3 CAS协议版本

版本 说明 特点
CAS 1.0 基础协议 简单认证流程
CAS 2.0 代理支持 支持代理认证
CAS 3.0 多协议 支持OAuth/SAML
CAS 4.0+ 企业特性 支持分布式、HA

二、CAS认证核心流程

2.1 标准认证流程

App2 CAS服务器 应用服务 用户浏览器 App2 CAS服务器 应用服务 用户浏览器 alt [首次登录] 后续访问其他应用 访问受保护资源 重定向到CAS登录页 显示登录表单 提交用户名密码 验证用户凭证 创建TGT 设置TGC Cookie 重定向到应用,携带ST 携带ST访问应用 验证ST有效性 验证成功,返回用户信息 返回受保护资源 访问应用2 重定向到CAS(携带TGC) 携带TGC 验证TGC有效 直接返回ST(无需登录) 携带ST访问应用2

2.2 协议详细步骤



失败
成功
无效
有效
无效
有效

  1. 用户访问App
    有TGC Cookie?
  2. 重定向到CAS登录
  3. 验证TGC
  4. 用户登录
    凭证验证
    显示错误
  5. 创建TGT
  6. 设置TGC Cookie
  7. 生成ST
  8. 重定向到App
    TGC有效?
  9. 生成ST
  10. App验证ST
    ST有效?
  11. 显示错误
  12. 返回用户信息
  13. 创建本地Session

2.3 服务票据ST特性

特性 说明
一次性 每个ST只能使用一次
时效性 通常5-10秒内必须使用
绑定服务 ST与请求的服务URL绑定
单向认证 只能验证用户身份,不能反向

三、票据机制详解

3.1 三层票据体系

ST内容
TGT内容
CAS服务器层
浏览器层
对应
生成
关系
TGC Cookie
TGT Session
ST 票据
用户身份
认证时间
过期时间
服务列表
目标服务URL
用户名
创建时间
父TGT ID

3.2 票据存储策略

java 复制代码
// CAS Server配置票据存储
@Configuration
public class TicketRegistryConfig {
    
    @Bean
    public TicketRegistry ticketRegistry() {
        // 1. 内存存储(开发环境)
        return new DefaultTicketRegistry();
        
        // 2. Redis存储(生产环境推荐)
        // return new RedisTicketRegistry();
        
        // 3. JPA存储(数据库)
        // return new JpaTicketRegistry();
    }
}

3.3 票据生命周期

java 复制代码
@Service
public class TicketLifecycleService {
    
    @Value("${cas.ticket.tgt.max-time-to-live-seconds:28800}")
    private int tgtMaxTimeToLive;
    
    @Value("${cas.ticket.tgt.timeout-seconds:7200}")
    private int tgtTimeOut;
    
    @Value("${cas.ticket.st.time-to-live-seconds:10}")
    private int stTimeToLive;
    
    /**
     * 创建TGT
     */
    public TicketGrantingTicket createTGT(String username) {
        // 1. 创建TGT
        TicketGrantingTicketImpl tgt = new TicketGrantingTicketImpl(
            TicketGrantingTicket.PREFIX,
            new SimplePrincipal(username),
            new EncryptedConcurrentHashMap<>(),
            tgtMaxTimeToLive,
            tgtTimeOut
        );
        
        // 2. 存储TGT
        ticketRegistry.addTicket(tgt);
        
        return tgt;
    }
    
    /**
     * 创建ST
     */
    public ServiceTicket createST(TicketGrantingTicket tgt, String serviceUrl) {
        // 1. 验证TGT有效性
        if (!tgt.isExpired()) {
            throw new TicketException("TGT expired");
        }
        
        // 2. 创建ST
        ServiceTicketImpl st = new ServiceTicketImpl(
            ServiceTicket.PREFIX,
            tgt,
            serviceUrl,
            stTimeToLive,
            serviceManager.isSsoEnabled()
        );
        
        // 3. 存储ST
        ticketRegistry.addTicket(st);
        
        return st;
    }
    
    /**
     * 验证ST
     */
    public Authentication verifyST(ServiceTicket st, String serviceUrl) {
        // 1. 检查ST是否已使用
        if (st.isConsumed()) {
            throw new TicketException("ST already consumed");
        }
        
        // 2. 检查ST是否过期
        if (st.isExpired()) {
            throw new TicketException("ST expired");
        }
        
        // 3. 检查服务URL匹配
        if (!st.getService().equals(serviceUrl)) {
            throw new TicketException("Service URL mismatch");
        }
        
        // 4. 标记ST已使用
        st.markConsumed();
        
        // 5. 返回认证信息
        return st.getGrantingTicket().getAuthentication();
    }
}

四、CAS Server部署配置

4.1 Docker部署

yaml 复制代码
# docker-compose.yml
version: '3.8'

services:
  cas:
    image: apereo/cas:6.6.10
    container_name: cas-server
    ports:
      - "8443:8443"
      - "8080:8080"
    environment:
      - CAS_SERVER_NAME=https://cas.example.com
      - CAS_SERVER_URL=https://cas.example.com:8443
      - SERVER_SSL_KEY_STORE=file:/etc/cas/thekeystore
      - SERVER_SSL_KEY_STORE_PASSWORD=changeit
      - SERVER_SSL_KEY_ALIAS=cas
      - DATABASE_HOST=postgres
      - DATABASE_PORT=5432
      - DATABASE_NAME=cas
      - DATABASE_USER=cas
      - DATABASE_PASSWORD=cas_password
      - DATABASE_DRIVER_CLASS=org.postgresql.Driver
      - DATABASE_DDL_AUTO=update
      - DATABASE_POOL_AUTOCOMMIT=true
      - DATABASE_POOL_MIN_SIZE=5
      - DATABASE_POOL_MAX_SIZE=20
      - DATABASE_POOL_TIMEOUT=30000
      - SPRING_JDBC_DRIVER_CLASS_NAME=org.postgresql.Driver
    volumes:
      - ./etc/cas:/etc/cas
      - ./keys:/etc/cas/keys
      - ./logs:/etc/cas/logs
    restart: unless-stopped
    networks:
      - cas-network

  postgres:
    image: postgres:15
    container_name: cas-postgres
    environment:
      - POSTGRES_DB=cas
      - POSTGRES_USER=cas
      - POSTGRES_PASSWORD=cas_password
    volumes:
      - postgres-data:/var/lib/postgresql/data
    restart: unless-stopped
    networks:
      - cas-network

volumes:
  postgres-data:

networks:
  cas-network:
    driver: bridge

4.2 应用配置

properties 复制代码
# application.properties
# 服务端点
cas.server.name=https://cas.example.com
cas.server.prefix=${cas.server.name}/cas

# 客户端回调
cas.client.host.url=http://app.example.com

# TGT配置
cas.ticket.tgt.max-time-to-live-seconds=28800
cas.ticket.tgt.timeout-seconds=7200

# ST配置
cas.ticket.st.time-to-live-seconds=10
cas.ticket.st.number-of-uses=1

# 数据库配置
spring.datasource.url=jdbc:postgresql://postgres:5432/cas
spring.datasource.username=cas
spring.datasource.password=cas_password
spring.datasource.driver-class-name=org.postgresql.Driver

# JPA配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.show-sql=false

# 日志配置
logging.config=file:/etc/cas/config/log4j2.xml

4.3 SSL证书配置

bash 复制代码
# 生成 keystore
keytool -genkey -alias cas \
  -keyalg RSA \
  -keysize 2048 \
  -keystore thekeystore \
  -storepass changeit \
  -keypass changeit \
  -dname "CN=cas.example.com, OU=IT, O=Example, L=Beijing, ST=Beijing, C=CN"

# 导出证书
keytool -export \
  -alias cas \
  -keystore thekeystore \
  -file cas.crt \
  -storepass changeit

# 导入到信任库
keytool -import \
  -alias cas \
  -file cas.crt \
  -keystore $JAVA_HOME/jre/lib/security/cacerts \
  -storepass changeit \
  -noprompt

4.4 高可用配置

yaml 复制代码
# cas-high-availability.yml
---
spring:
  profiles: ha
  
  # Redis共享Session
  session:
    store-type: redis
    redis:
      namespace: cas:session
      timeout: 3600s
      
  # Redis连接
  data:
    redis:
      host: redis-master
      port: 6379
      password: ${REDIS_PASSWORD:}
      timeout: 5000ms
      lettuce:
        pool:
          max-active: 20
          max-idle: 10
          min-idle: 5

  # 多数据源
  datasource:
    primary:
      url: jdbc:postgresql://postgres-primary:5432/cas
      hikari:
        maximum-pool-size: 20
        minimum-idle: 5
    replica:
      url: jdbc:postgresql://postgres-replica:5432/cas
      hikari:
        maximum-pool-size: 20
        minimum-idle: 5

五、CAS Client集成

5.1 Maven依赖

xml 复制代码
<!-- CAS Client -->
<dependency>
    <groupId>org.apereo.cas.client</groupId>
    <artifactId>cas-client-core</artifactId>
    <version>3.6.4</version>
</dependency>

<!-- Spring Security CAS集成 -->
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-cas</artifactId>
</dependency>

5.2 Spring Security CAS配置

java 复制代码
@Configuration
@EnableWebSecurity
public class CasSecurityConfig {
    
    @Value("${cas.server-url-prefix}")
    private String casServerUrlPrefix;
    
    @Value("${cas.server-login-url}")
    private String casServerLoginUrl;
    
    @Value("${cas.server-logout-url}")
    private String casServerLogoutUrl;
    
    @Value("${app.server-url}")
    private String appServerUrl;
    
    @Value("${cas.validation-url}")
    private String casValidationUrl;
    
    @Bean
    public ServiceProperties serviceProperties() {
        ServiceProperties properties = new ServiceProperties();
        properties.setService(appServerUrl + "/login/cas");
        properties.setSendRenew(false);  // 不强制每次都登录
        properties.setAuthenticateAllArtifacts(false);
        return properties;
    }
    
    @Bean
    public TicketValidator ticketValidator() {
        // CAS 3.x 协议验证器
        return new Cas30ServiceTicketValidator(casServerUrlPrefix);
    }
    
    @Bean
    public CasAuthenticationProvider casAuthenticationProvider() {
        CasAuthenticationProvider provider = new CasAuthenticationProvider();
        provider.setKey("CasAuthenticationProvider");
        provider.setTicketValidator(ticketValidator());
        provider.setServiceProperties(serviceProperties());
        provider.setAuthenticationUserDetailsService(
            new CustomAuthenticationUserDetailsService());
        return provider;
    }
    
    @Bean
    public CasAuthenticationFilter casAuthenticationFilter() {
        CasAuthenticationFilter filter = new CasAuthenticationFilter();
        filter.setAuthenticationManager(authenticationManager());
        filter.setServiceProperties(serviceProperties());
        filter.setFilterProcessesUrl("/login/cas");
        return filter;
    }
    
    @Bean
    public SecurityFilterChain casFilterChain(HttpSecurity http) throws Exception {
        http
            .addFilterBefore(casAuthenticationFilter(), 
                UsernamePasswordAuthenticationFilter.class)
            
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/public/**", "/login", "/error").permitAll()
                .requestMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated())
            
            .exceptionHandling(ex -> ex
                .authenticationEntryPoint(new CasAuthenticationEntryPoint()))
            
            .logout(logout -> logout
                .logoutUrl("/logout")
                .logoutSuccessHandler(casLogoutSuccessHandler())
                .invalidateHttpSession(true)
                .deleteCookies("JSESSIONID"));
        
        return http.build();
    }
    
    @Bean
    public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {
        CasAuthenticationEntryPoint entryPoint = 
            new CasAuthenticationEntryPoint();
        entryPoint.setLoginUrl(casServerLoginUrl);
        entryPoint.setServiceProperties(serviceProperties());
        return entryPoint;
    }
    
    @Bean
    public LogoutSuccessHandler casLogoutSuccessHandler() {
        SimpleUrlLogoutSuccessHandler handler = 
            new SimpleUrlLogoutSuccessHandler();
        handler.setDefaultTargetUrl("/");
        handler.setAlwaysUseDefaultTargetUrl(false);
        
        // CAS单点登出
        CasLogoutSuccessHandler casHandler = new CasLogoutSuccessHandler();
        casHandler.setCasServerUrlPrefix(casServerUrlPrefix);
        casHandler.setDefaultTargetUrl("/");
        return casHandler;
    }
}

5.3 自定义用户详情服务

java 复制代码
public class CustomAuthenticationUserDetailsService 
        implements AuthenticationUserDetailsService<CasAssertionAuthenticationToken> {
    
    @Autowired
    private UserService userService;
    
    @Override
    public UserDetails loadUserDetails(
            CasAssertionAuthenticationToken token) throws UsernameNotFoundException {
        
        // 1. 从CAS获取用户信息
        String username = token.getName();
        Assertion assertion = token.getAssertion();
        
        // 2. 获取CAS返回的附加属性
        Map<String, Object> attributes = assertion.getAttributes();
        String email = (String) attributes.get("email");
        String displayName = (String) attributes.get("displayName");
        List<String> roles = (List<String>) attributes.get("roles");
        
        // 3. 查询本地用户或创建新用户
        User user = userService.findByUsername(username)
            .orElseGet(() -> createUserFromCas(username, email, displayName));
        
        // 4. 更新用户信息
        user.setLastLoginTime(new Date());
        userService.save(user);
        
        // 5. 返回UserDetails
        return User.builder()
            .username(user.getUsername())
            .password("")  // CAS认证不需要密码
            .authorities(roles.stream()
                .map(role -> new SimpleGrantedAuthority("ROLE_" + role))
                .toArray(GrantedAuthority[]::new))
            .accountExpired(false)
            .accountLocked(!user.isEnabled())
            .credentialsExpired(false)
            .disabled(!user.isEnabled())
            .build();
    }
    
    private User createUserFromCas(String username, String email, 
                                   String displayName) {
        User user = new User();
        user.setUsername(username);
        user.setEmail(email);
        user.setDisplayName(displayName);
        user.setEnabled(true);
        user.setCreateTime(new Date());
        return userService.save(user);
    }
}

5.4 票据验证服务

java 复制代码
@Service
public class CasTicketValidationService {
    
    private final TicketValidator ticketValidator;
    private final ServiceProperties serviceProperties;
    
    /**
     * 验证CAS票据
     */
    public Authentication validateTicket(String ticket, String service) {
        try {
            // 1. 构建服务URL
            Assertion assertion = ticketValidator.validate(ticket, service);
            
            // 2. 提取用户信息
            Principal principal = assertion.getPrincipal();
            String username = principal.getName();
            Map<String, Object> attributes = principal.getAttributes();
            
            // 3. 构建认证信息
            return new UsernamePasswordAuthenticationToken(
                username, null,
                extractAuthorities(attributes)
            );
            
        } catch (TicketValidationException e) {
            throw new AuthenticationException("CAS ticket validation failed", e);
        }
    }
    
    /**
     * 从CAS属性提取权限
     */
    private Collection<GrantedAuthority> extractAuthorities(
            Map<String, Object> attributes) {
        
        List<GrantedAuthority> authorities = new ArrayList<>();
        
        // 从roles属性提取
        List<String> roles = (List<String>) attributes.get("roles");
        if (roles != null) {
            roles.forEach(role -> 
                authorities.add(new SimpleGrantedAuthority("ROLE_" + role)));
        }
        
        // 从authorities属性提取
        List<String> auths = (List<String>) attributes.get("authorities");
        if (auths != null) {
            auths.forEach(auth -> 
                authorities.add(new SimpleGrantedAuthority(auth)));
        }
        
        return authorities;
    }
}

六、跨域SSO方案

6.1 跨域Cookie方案

java 复制代码
@Configuration
public class CrossDomainCasConfig {
    
    @Value("${cas.server-domain}")
    private String casServerDomain;
    
    @Bean
    public CookieGenerator ticketGrantingTicketCookieGenerator() {
        CookieGenerator generator = new CookieGenerator();
        generator.setCookieName("TGC");
        generator.setCookieDomain(casServerDomain);  // 跨域Cookie
        generator.setCookieMaxAge(-1);  // Session级别
        generator.setCookiePath("/");
        generator.setuseHttpOnly(true);
        generator.setsameSiteValue("Strict");
        return generator;
    }
}

6.2 TicketRelay跨域方案

应用B CAS服务器 应用A 用户代理 应用B CAS服务器 应用A 用户代理 登录 重定向 登录 设置TGC + 重定向 携带ST 验证ST 登录成功 访问 重定向(ticketRelayService参数) 重定向回App2 携带ST 验证ST 登录成功

java 复制代码
@Configuration
public class TicketRelayConfig {
    
    /**
     * 跨域票据转发
     */
    @Bean
    public TicketRelayService ticketRelayService() {
        return new TicketRelayServiceImpl();
    }
}

@Service
public class TicketRelayServiceImpl implements TicketRelayService {
    
    @Override
    public String getTargetService(HttpServletRequest request) {
        String service = request.getParameter("targetService");
        if (service != null) {
            return URLDecoder.decode(service, StandardCharsets.UTF_8);
        }
        
        // 从请求属性获取(过滤器设置)
        return (String) request.getAttribute("targetService");
    }
    
    @Override
    public String buildRedirectUrl(String service, String ticket) {
        String delimiter = service.contains("?") ? "&" : "?";
        return service + delimiter + "ticket=" + ticket;
    }
}

七、CAS安全加固

7.1 协议安全配置

properties 复制代码
# 协议安全配置
cas.security.cas.tgc.enabled=true
cas.security.cas.tgc.remember-me.enabled=false
cas.security.cas.tgc.crypto.enabled=true
cas.security.cas.tgc.crypto.alg=AES
cas.security.cas.tgc.crypto.key.size=256

# 票据加密
cas.security.ticket.st.crypto.enabled=true
cas.security.ticket.tgt.crypto.enabled=true
cas.security.ticket.core.encryption.key=your-encryption-key
cas.security.ticket.core.signing.key=your-signing-key

# 代理票据安全
cas.proxy.authn.max.number.of.proxies=10
cas.proxy.callback.url.allowed=.*

7.2 登录限流

java 复制代码
@Configuration
public class LoginRateLimitConfig {
    
    @Value("${cas.authn.ip.rate.limit.enabled:true}")
    private boolean rateLimitEnabled;
    
    @Value("${cas.authn.ip.rate.limit.max-attempts:10}")
    private int maxAttempts;
    
    @Value("${cas.authn.ip.rate.limit.window-seconds:60}")
    private int windowSeconds;
    
    @Bean
    public IPAddressAuthenticationHandler ipAuthenticationHandler() {
        return new IPAddressAuthenticationHandler(
            rateLimitEnabled,
            maxAttempts,
            windowSeconds
        );
    }
}

public class IPAddressAuthenticationHandler 
        implements AuthenticationHandler {
    
    private final RateLimiter rateLimiter;
    
    @Override
    public Authentication authenticate(AuthenticationTransaction transaction) 
            throws AuthenticationException {
        
        String ipAddress = transaction.getProperties()
            .get("clientIpAddress");
        
        // 检查IP是否被限制
        if (rateLimiter.isLimited(ipAddress)) {
            throw new FailedLoginException("Too many authentication attempts");
        }
        
        // 执行认证逻辑
        Authentication result = doAuthenticate(transaction);
        
        // 认证失败,记录
        if (result == null) {
            rateLimiter.recordFailure(ipAddress);
        } else {
            rateLimiter.recordSuccess(ipAddress);
        }
        
        return result;
    }
}

7.3 审计日志

java 复制代码
@Configuration
public class AuditConfig {
    
    @Bean
    public AuditTrailManager auditTrailManager() {
        return new JpaAuditTrailManager();
    }
}

@Service
public class CasAuditService {
    
    @Autowired
    private AuditTrailManager auditTrailManager;
    
    public void audit(String who, String what, String action, 
                     String resource, boolean success) {
        
        AuditAction auditAction = AuditAction.create(who, what, action);
        
        Map<String, Object> data = new HashMap<>();
        data.put("resource", resource);
        data.put("success", success);
        data.put("timestamp", Instant.now());
        data.put("ipAddress", getClientIp());
        data.put("userAgent", getUserAgent());
        
        auditAction.setData(data);
        
        auditTrailManager.record(auditAction);
    }
}

八、CAS与OAuth2/OIDC集成

8.1 CAS as OAuth2 Provider

properties 复制代码
# 启用OAuth2
cas.authn.oauth.enabled=true
cas.authn.oauth.refreshToken.timeToKillInSeconds=2592000
cas.authn.oauth.code.timeToKillInSeconds=60

# OAuth2客户端注册
cas.oauth.provider.name=CAS
cas.oauth.provider.display-name=CAS OAuth Server

8.2 CAS OIDC配置

properties 复制代码
# 启用OIDC
cas.authn.oidc.enabled=true
cas.authn.oidc.discovery.discoveryUri=https://cas.example.com/.well-known/openid-configuration

# 签名密钥
cas.authn.oidc.core.signingJwksUri=file:/etc/cas/oidc-signing.jwks
cas.authn.oidc.core.encryptionJwksUri=file:/etc/cas/oidc-encryption.jwks

# 作用域
cas.authn.oidc.core.defaultScopes=openid,profile,email
cas.authn.oidc.core.availableScopes=openid,profile,email,address,phone

8.3 第三方应用集成

java 复制代码
@Configuration
public class OidcClientConfig {
    
    @Bean
    public OAuth2AuthorizedClientService authorizedClientService(
            ClientRegistrationRepository registrations) {
        return new InMemoryOAuth2AuthorizedClientService(registrations);
    }
    
    @Bean
    public OAuth2LoginAuthenticationProvider oidcProvider(
            OAuth2UserService<OIDCUserRequest, OIDCUser> userService) {
        return new OAuth2LoginAuthenticationProvider(
            new DefaultOAuth2AuthorizationClientProvider(),
            userService
        );
    }
}

九、常见问题处理

9.1 票据相关问题

问题 原因 解决方案
ST无效 ST已使用或过期 检查ST有效期内使用
TGT过期 会话超时 重新登录
票据不匹配 Service URL不一致 检查URL格式
票据无法验证 CAS Server时钟不同步 同步NTP

9.2 性能问题

java 复制代码
// 票据缓存配置
@Configuration
public class TicketCachingConfig {
    
    @Bean
    public ConcurrentMapCacheManager ticketCacheManager() {
        ConcurrentMapCacheManager manager = new ConcurrentMapCacheManager();
        manager.setCacheNames(Arrays.asList(
            "ticketValidationCache",
            "proxyGrantingTicketCache"
        ));
        return manager;
    }
    
    @Cacheable(value = "ticketValidationCache", 
               key = "#ticket + #service")
    public Assertion validateAndCache(String ticket, String service) {
        return ticketValidator.validate(ticket, service);
    }
}

9.3 集群会话同步

java 复制代码
@Configuration
@EnableRedisHttpSession
public class RedisSessionConfig {
    
    @Bean
    public ConfigBeanWrapper<RedisIndexedSessionRepository> sessionRepository(
            RedisConnectionFactory factory) {
        
        RedisIndexedSessionRepository repository = 
            new RedisIndexedSessionRepository(factory);
        
        repository.setDefaultSerializer(new JdkSerializationRedisSerializer());
        repository.setFlushMode(RedisFlushMode.ON_SAVE);
        repository.setSaveMode(SaveMode.ON_SET_ATTRIBUTE);
        
        return new ConfigBeanWrapper<>(repository);
    }
}

十、总结

10.1 CAS部署架构

应用层
数据层
CAS集群
负载均衡层
负载均衡器
CAS Server 1
CAS Server 2
CAS Server 3
PostgreSQL
Redis
应用A
应用B
应用C

10.2 关键配置检查表

配置项 说明 状态
HTTPS配置 SSL证书配置
TGT过期时间 默认2小时
ST过期时间 默认10秒
票据加密 AES-256加密
登录限流 防暴力破解
审计日志 记录认证事件
单点登出 SLO配置
高可用 集群部署

10.3 与其他方案对比

特性 CAS OAuth2 JWT
协议复杂度
单点登录 ✅ 原生支持 ⚠️ 需扩展
单点登出 ✅ 原生支持 ⚠️ 需扩展
第三方登录 ⚠️ 需配置 ✅ 原生支持
移动端支持 ⚠️
微服务认证 ⚠️
学习成本

CAS作为成熟的企业级SSO解决方案,在单点登录场景下具有明显优势。掌握其协议原理和配置方法,能够帮助企业快速构建统一认证体系。

相关推荐
知兀8 小时前
【微服务/nacos】Nacos注册中心原理;配置服务发现中间、配置中心
java·微服务·架构
DevilSeagull8 小时前
Rust 枚举(enum)深度解析:从定义到 Option 的安全之道
开发语言·后端·安全·rust·github
一 乐8 小时前
茶叶商城|基于springboot + vue茶叶商城系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·茶叶商城系统
AI进化营-智能译站9 小时前
ROS2 C++开发系列06:变量、数据类型与IO实战
java·开发语言·c++·ai
薪火铺子10 小时前
OAuth2 + JWT 微服务认证方案深度解析
java·运维·微服务
diangedan11 小时前
Android冻屏
android·java
abcnull17 小时前
用javaparser做精准测试
java·ast·静态代码分析·精准测试·javaparser
叶小鸡17 小时前
Java 篇-项目实战-苍穹外卖-笔记汇总
java·开发语言·笔记
AI人工智能+电脑小能手17 小时前
【大白话说Java面试题】【Java基础篇】第22题:HashMap 和 HashSet 有哪些区别
java·开发语言·哈希算法·散列表·hash