Springboot之整合cas client

本文详细介绍如何在SpringBoot项目中整合CASClient实现单点登录和单点注销功能,包括XML配置方式与JavaConfig配置方式,并介绍如何通过注解@EnableCasClient简化配置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Springboot之整合cas client

CAS client在github的示例项目使用的是web.xml来配置过滤器
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
​
<!--
   <context-param>
       <param-name>renew</param-name>
       <param-value>true</param-value>
   </context-param>
-->
​
    <filter>
        <filter-name>CAS Single Sign Out Filter</filter-name>
        <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
        <init-param>
            <param-name>casServerUrlPrefix</param-name>
            <param-value>https://mmoayyed.unicon.net:8443/cas</param-value>
        </init-param>
    </filter>
​
    <listener>
        <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
    </listener>
​
    <filter>
        <filter-name>CAS Authentication Filter</filter-name>
        <!--<filter-class>org.jasig.cas.client.authentication.Saml11AuthenticationFilter</filter-class>-->
        <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
        <init-param>
            <param-name>casServerLoginUrl</param-name>
            <param-value>https://mmoayyed.unicon.net:8443/cas/login</param-value>
        </init-param>
        <init-param>
            <param-name>serverName</param-name>
            <param-value>https://mmoayyed.unicon.net:9443</param-value>
        </init-param>
    </filter>
​
    <filter>
        <filter-name>CAS Validation Filter</filter-name>
        <!--<filter-class>org.jasig.cas.client.validation.Saml11TicketValidationFilter</filter-class>-->
        <filter-class>org.jasig.cas.client.validation.Cas30ProxyReceivingTicketValidationFilter</filter-class>
        <init-param>
            <param-name>casServerUrlPrefix</param-name>
            <param-value>https://mmoayyed.unicon.net:8443/cas</param-value>
        </init-param>
        <init-param>
            <param-name>serverName</param-name>
            <param-value>https://mmoayyed.unicon.net:9443</param-value>
        </init-param>
        <init-param>
            <param-name>redirectAfterValidation</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>useSession</param-name>
            <param-value>true</param-value>
        </init-param>
        <!--
        <init-param>
            <param-name>acceptAnyProxy</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>proxyReceptorUrl</param-name>
            <param-value>/sample/proxyUrl</param-value>
        </init-param>
        <init-param>
            <param-name>proxyCallbackUrl</param-name>
            <param-value>https://mmoayyed.unicon.net:9443/sample/proxyUrl</param-value>
        </init-param>
        -->
        <init-param>
            <param-name>authn_method</param-name>
            <param-value>mfa-duo</param-value>
        </init-param>
    </filter>
​
    <filter>
        <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
        <filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
    </filter>
​
    <filter-mapping>
        <filter-name>CAS Single Sign Out Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
​
    <filter-mapping>
        <filter-name>CAS Validation Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
​
    <filter-mapping>
        <filter-name>CAS Authentication Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
​
    <filter-mapping>
        <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
​
    <welcome-file-list>
        <welcome-file>
            index.jsp
        </welcome-file>
    </welcome-file-list>
</web-app>

但是Springboot项目当中不使用xml文件配置,使用Java config配置注解,这也不是什么难事,配置如下:

import java.util.EventListener;
import java.util.HashMap;
import java.util.Map;
​
import javax.servlet.Filter;
​
import org.jasig.cas.client.authentication.AuthenticationFilter;
import org.jasig.cas.client.session.SingleSignOutFilter;
import org.jasig.cas.client.session.SingleSignOutHttpSessionListener;
import org.jasig.cas.client.util.HttpServletRequestWrapperFilter;
import org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter;
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;
​
/**
* @author Barry
* @date   2018年9月20日 下午2:10:47
*/
@Configuration
public class CasFilterConfig {
    
    private static final String CAS_SERVER_URL_PREFIX = "http://localhost:8900/cas";
    
    private static final String SERVER_NAME = "http://localhost:9988";
    /**
     * SingleSignOutFilter
      * 必须放在最前面
     */
    @Bean
    public FilterRegistrationBean<SingleSignOutFilter> filterSingleRegistration() {
        FilterRegistrationBean<SingleSignOutFilter> registration = new FilterRegistrationBean<SingleSignOutFilter>();
        registration.setFilter(new SingleSignOutFilter());
        Map<String,String> initParameters = new HashMap<String,String>();
        initParameters.put("casServerUrlPrefix",CAS_SERVER_URL_PREFIX );
        registration.setInitParameters(initParameters);
        //set mapping url
        registration.addUrlPatterns("/*");
        //set loading sequence
        registration.setOrder(1);
        return registration;
    }
    
    
    /**
     * 添加监听器
     * @return
     */
    @Bean  
    public ServletListenerRegistrationBean<EventListener> singleSignOutListenerRegistration(){  
        ServletListenerRegistrationBean<EventListener> registrationBean = new ServletListenerRegistrationBean<EventListener>();  
        registrationBean.setListener(new SingleSignOutHttpSessionListener());  
        registrationBean.setOrder(1);  
        return registrationBean;  
    } 
    
    /**
     *  授权过滤器
     * @return
     */
    @Bean
    public FilterRegistrationBean<AuthenticationFilter> filterAuthenticationRegistration() {
        FilterRegistrationBean<AuthenticationFilter> registration = new FilterRegistrationBean<AuthenticationFilter>();
        registration.setFilter(new AuthenticationFilter());
        // 设定匹配的路径
        registration.addUrlPatterns("/*");
        Map<String,String>  initParameters = new HashMap<String, String>();
        initParameters.put("casServerLoginUrl", CAS_SERVER_URL_PREFIX);
        initParameters.put("serverName", SERVER_NAME);
        registration.setInitParameters(initParameters);
        //设定加载的顺序
        registration.setOrder(1);
        return registration;
    }
    
    /**
     * CAS Validation Filter
     * @return
     */
    @Bean
    public FilterRegistrationBean<Filter> filterValidationRegistration() {
        FilterRegistrationBean<Filter> registration  = new FilterRegistrationBean<>();
        registration.setFilter(new Cas20ProxyReceivingTicketValidationFilter());
        //set mapping url
        registration.addUrlPatterns("/*");
        Map<String,String>  initParameters = new HashMap<String, String>();
        initParameters.put("casServerUrlPrefix", CAS_SERVER_URL_PREFIX);
        initParameters.put("serverName", SERVER_NAME);
        initParameters.put("useSession", "true");
        registration.setInitParameters(initParameters);
        registration.setOrder(1);
        return registration;
    }
    
    /**
     * wraper过滤器
     * @return
     */
    @Bean
    public FilterRegistrationBean<HttpServletRequestWrapperFilter> filterWrapperRegistration() {
        FilterRegistrationBean<HttpServletRequestWrapperFilter> registration = new FilterRegistrationBean<HttpServletRequestWrapperFilter>();
        registration.setFilter(new HttpServletRequestWrapperFilter());
        // 设定匹配的路径
        registration.addUrlPatterns("/*");
        // 设定加载的顺序
        registration.setOrder(1);
        return registration;
    }
}
​
​

这样就可以拦截请求,转到cas server登录和退出。

但是Springboot是个爸爸呀,默认大于配置,因此很多东西都有默认的配置,这种事怎么可能没做呢!原来启用注解@EnableCasClient即可。但是需要在pom文件中引入包

	<dependency>
		    <groupId>net.unicon.cas</groupId>
		    <artifactId>cas-client-autoconfig-support</artifactId>
		    <version>1.7.0-GA</version>
		</dependency>
       

查看源码

 @Bean
    public FilterRegistrationBean casAuthenticationFilter() {
        final FilterRegistrationBean authnFilter = new FilterRegistrationBean();
        final Filter targetCasAuthnFilter =
                (this.configProps.getValidationType() == CAS || configProps.getValidationType() == CAS3) ? new AuthenticationFilter()
                        : new Saml11AuthenticationFilter();
​
        initFilter(authnFilter,
                targetCasAuthnFilter,
                2,
                constructInitParams("casServerLoginUrl", this.configProps.getServerLoginUrl(), this.configProps.getClientHostUrl()),
                this.configProps.getAuthenticationUrlPatterns());
​
        if (this.configProps.getGateway() != null) {
            authnFilter.getInitParameters().put("gateway", String.valueOf(this.configProps.getGateway()));
        }
​
        if (this.casClientConfigurer != null) {
            this.casClientConfigurer.configureAuthenticationFilter(authnFilter);
        }
        return authnFilter;
    }
​
​
    @Bean
    public FilterRegistrationBean casHttpServletRequestWrapperFilter() {
        final FilterRegistrationBean reqWrapperFilter = new FilterRegistrationBean();
        reqWrapperFilter.setFilter(new HttpServletRequestWrapperFilter());
        if (this.configProps.getRequestWrapperUrlPatterns().size() > 0) {
            reqWrapperFilter.setUrlPatterns(this.configProps.getRequestWrapperUrlPatterns());
        }
        reqWrapperFilter.setOrder(3);
​
        if (this.casClientConfigurer != null) {
            this.casClientConfigurer.configureHttpServletRequestWrapperFilter(reqWrapperFilter);
        }
        return reqWrapperFilter;
    }
​
    @Bean
    public FilterRegistrationBean casAssertionThreadLocalFilter() {
        final FilterRegistrationBean assertionTLFilter = new FilterRegistrationBean();
        assertionTLFilter.setFilter(new AssertionThreadLocalFilter());
        if (this.configProps.getAssertionThreadLocalUrlPatterns().size() > 0) {
            assertionTLFilter.setUrlPatterns(this.configProps.getAssertionThreadLocalUrlPatterns());
        }
        assertionTLFilter.setOrder(4);
​
        if (this.casClientConfigurer != null) {
            this.casClientConfigurer.configureAssertionThreadLocalFilter(assertionTLFilter);
        }
        return assertionTLFilter;
    }
​
​
    @Autowired(required = false)
    void setConfigurers(Collection<CasClientConfigurer> configurers) {
        if (CollectionUtils.isEmpty(configurers)) {
            return;
        }
        if (configurers.size() > 1) {
            throw new IllegalStateException(configurers.size() + " implementations of " +
                    "CasClientConfigurer were found when only 1 was expected. " +
                    "Refactor the configuration such that CasClientConfigurer is " +
                    "implemented only once or not at all.");
        }
        this.casClientConfigurer = configurers.iterator().next();
    }
​
    private Map<String, String> constructInitParams(final String casUrlParamName, final String casUrlParamVal, final String clientHostUrlVal) {
        final Map<String, String> initParams = new HashMap<>(2);
        initParams.put(casUrlParamName, casUrlParamVal);
        initParams.put("serverName", clientHostUrlVal);
        return initParams;
    }
​
    private void initFilter(final FilterRegistrationBean filterRegistrationBean,
                            final Filter targetFilter,
                            int filterOrder,
                            final Map<String, String> initParams,
                            List<String> urlPatterns) {
​
        filterRegistrationBean.setFilter(targetFilter);
        filterRegistrationBean.setOrder(filterOrder);
        filterRegistrationBean.setInitParameters(initParams);
        if (urlPatterns.size() > 0) {
            filterRegistrationBean.setUrlPatterns(urlPatterns);
        }
    }

但是比较诡异的是,貌似该注解下没有SingleSignOutFilter过滤器,我暂时还没有搞清楚。不过可以继承CasClientConfigurerAdapter类进行自定义。

### Spring Boot 3与CAS集成指南 #### 准备工作 为了使Spring Boot 3应用程序能够利用CAS进行单点登录(SSO),需先完成一些准备工作。确保已安装并配置好CAS服务器[^1]。 #### 添加依赖项 在`pom.xml`文件中加入必要的Maven依赖来支持Spring Security以及CAS客户端功能: ```xml <dependency> <groupId>org.apereo.cas.client</groupId> <artifactId>cas-client-support-saml</artifactId> <version>${cas.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> ``` 以上代码片段展示了如何引入Apereo CAS SAML模块和支持安全性的启动器包,这有助于简化SSO流程中的认证处理逻辑。 #### 配置Security设置 创建或编辑位于资源目录下的`application.yml`文件,定义如下属性以适应特定环境需求: ```yaml server: port: 8080 security: cas: login-url: https://your-cas-server/cas/login service-url: http://localhost:${server.port}/login/cas logout-url: https://your-cas-server/cas/logout?url=http://localhost:${server.port} spring: security: user: name: "user" password: "{noop}password" ``` 此部分设置了服务端口、CAS登录地址和服务URL等参数,其中`${}`用于动态获取其他地方定义过的变量值;同时指定了退出后的重定向链接。 #### 自定义过滤器链 通过覆盖默认的安全配置类来自定义身份验证机制,在此类内部实现对请求路径模式匹配的功能,并注册相应的过滤组件实例化对象至HttpSecurity对象内: ```java @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/css/**", "/js/**").permitAll() // Allow access to static resources without authentication. .anyRequest().authenticated(); // Require all other requests be authenticated. CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter(); casAuthenticationFilter.setServiceProperties(serviceProperties()); SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter(); http.addFilter(casAuthenticationFilter).addFilterBefore(singleSignOutFilter,CasAuthenticationFilter.class); } @Bean public ServiceProperties serviceProperties(){ ServiceProperties sp = new ServiceProperties(); sp.setService("http://localhost:8080/your-app/j_spring_cas_security_check"); sp.setSendRenew(false); return sp; } } ``` 上述Java代码实现了自定义的安全配置策略,包括允许未经过身份验证即可访问静态资源(如CSS和JavaScript),而其余所有请求都需要经过身份验证才能继续执行下去。此外还初始化了一个`CasAuthenticationFilter`实例用来拦截受保护页面的HTTP GET方法调用,并将其转发给指定的服务提供者接口(SP)。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值