springboot 适配CAS单点登录

公司的springboot框架适配客户的单点登录服务器时遇到一些问题,记录下来方便自己以后参考。
  1. 客户提供的单点登录demo是适用于web.xml配置的样例





  Welcome to Tomcat
  
     Welcome to Tomcat
  

    
    
        CAS Single Sign Out Filter
        org.jasig.cas.client.session.SingleSignOutFilter
    
    
        CAS Single Sign Out Filter
        /*
    
    
        org.jasig.cas.client.session.SingleSignOutHttpSessionListener
    

    
    
        CASFilter
        org.jasig.cas.client.authentication.AuthenticationFilter
        
        
            casServerLoginUrl
            http://xxx.xxx.xxx.xxx:xxxx/cas/login

        
        
            renew
            false
        
        
            gateway
            false
        
        
        
            serverName
            http://xxx.xxx.xxx.xxx:xxxx/
        
    
    
        CASFilter
        /loginsso.jsp
    
    
    
        CAS Validation Filter
        
            org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter
        
            casServerUrlPrefix
            http://xxx.xxx.xxx.xxx:xxxx//cas
        
        
            serverName
            http://xxx.xxx.xxx.xxx:xxxx/
        
        
            useSession
            true
        
        
            redirectAfterValidation
            true
        

    
    
        CAS Validation Filter
        /loginsso.jsp
    

    
        CAS HttpServletRequest Wrapper Filter
        
            org.jasig.cas.client.util.HttpServletRequestWrapperFilter
    
    
        CAS HttpServletRequest Wrapper Filter
        /loginsso.jsp
    

    
        CAS Assertion Thread Local Filter
        org.jasig.cas.client.util.AssertionThreadLocalFilter
    
    
        CAS Assertion Thread Local Filter
        /loginsso.jsp
    
    
    
    
        setnameFilter
        com.loginsso.ClientFilter
        
            uumsServiceUrl
            http://xxx.xxx.xxx.xxx:xxxx//UUMS/services/UUMSService
        
    
        appName
        admin
    
    
        setSessionClass
        com.loginsso.LoginSetSession
    
    
    
        setnameFilter
        /loginsso.jsp
    
    



  1. 将客户所提供的demo中的filter以springboot的方式加载
package com;

import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;

import org.jasig.cas.client.session.SingleSignOutFilter;
import org.jasig.cas.client.session.SingleSignOutHttpSessionListener;
import org.jasig.cas.client.util.AssertionThreadLocalFilter;
import org.jasig.cas.client.util.HttpServletRequestWrapperFilter;
import org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.context.annotation.Configuration;

import com.lyarc.corp.filter.AuthenticationFilter;
import com.lyarc.corp.filter.ClientFilter;
import com.lyarc.engine.utils.SpringUtil;


@Configuration
public class MyWebApplicationInitializer implements ServletContextInitializer {
    
    private static final String mp="/count/list";
    
    //private static final String casServer="http://xxx.xxx.xxx.xxx:xxxx";
    //private static final String serverName="http://xxx.xxx.xxx.xxx:xxxx";
    
    //本地环境模拟地址,发布时用上面一组配置
    private static final String casServer="http://xxx.xxx.xxx.xxx:xxxx";
    private static final String serverName="http://xxx.xxx.xxx.xxx:xxxx";
    //private static final String serverName="http://xxx.xxx.xxx.xxx:xxxx";
    
    @Override
    public void onStartup(ServletContext sc) {
        //单点登出
        FilterRegistration.Dynamic cASLogoutFilter = sc.addFilter("CAS Single Sign Out Filter", SingleSignOutFilter.class);
        cASLogoutFilter.addMappingForUrlPatterns(null, false, "/*");
        sc.addListener(SingleSignOutHttpSessionListener.class);
        
        //单点登录
        FilterRegistration.Dynamic cASLoginFilter = sc.addFilter("CASFilter", AuthenticationFilter.class);
        //CAS login 服务地址
        cASLoginFilter.setInitParameter("casServerLoginUrl", casServer+"/cas/login");
        cASLoginFilter.setInitParameter("renew", "false");
        cASLoginFilter.setInitParameter("gateway", "false");
        //客户端应用服务地址
        cASLoginFilter.setInitParameter("serverName", serverName);
        cASLoginFilter.setInitParameter("ignoreInterface", "xxx/xxx/xxx");
        //此处修改成XX系统新增的跳转页面      
        cASLoginFilter.addMappingForUrlPatterns(null, false, mp);
                
        //负责Ticket校验
        FilterRegistration.Dynamic cASValidationFilter = sc.addFilter("CAS Validation Filter", Cas20ProxyReceivingTicketValidationFilter.class);
        
        cASValidationFilter.setInitParameter("casServerUrlPrefix", casServer+"/cas");
        cASValidationFilter.setInitParameter("serverName", serverName);

        cASValidationFilter.setInitParameter("useSession", "true");
        cASValidationFilter.setInitParameter("redirectAfterValidation", "true");
        //此处修改成XX系统新增的跳转页面
        cASValidationFilter.addMappingForUrlPatterns(null, false, mp);
                
        FilterRegistration.Dynamic cASWrapperFilter = sc.addFilter("CAS HttpServletRequest Wrapper Filter", HttpServletRequestWrapperFilter.class);
        //此处修改成XX系统新增的跳转页面
        cASWrapperFilter.addMappingForUrlPatterns(null, false, "/xxx/xxx");
               
        FilterRegistration.Dynamic cASThreadLocalFilter = sc.addFilter("CAS Assertion Thread Local Filter", AssertionThreadLocalFilter.class);
        //此处修改成XX系统新增的跳转页面
        cASThreadLocalFilter.addMappingForUrlPatterns(null, false, mp);
                
        //负责Ticket校验
        FilterRegistration.Dynamic cASSetName = sc.addFilter("setnameFilter", ClientFilter.class);
        cASSetName.setInitParameter("uumsServiceUrl", casServer+"/UUMS/services/UUMSService");
        cASSetName.setInitParameter("appName", "xxx");
        cASSetName.setInitParameter("setSessionClass", "xxx.xxx.xxx.xxx.LoginSetSession");
        //此处修改成XX系统新增的跳转页面
        cASSetName.addMappingForUrlPatterns(null, false, mp);
    }
}

也可以通过bean的方式加载filter

@Bean
    public FilterRegistrationBean filterRegistrationSingleSignOutFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new SingleSignOutFilter());
        registration.addUrlPatterns("/*");
        registration.setOrder(1);
        return registration;
    }
    @Bean
    public FilterRegistrationBean filterRegistrationAuthenticationFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new AuthenticationFilter());
        //CAS login 服务地址
        registration.addInitParameter("casServerLoginUrl", "http://xxx.xxx.xxx.xxx:xxx/cas/login");
        registration.addInitParameter("renew", "false");
        registration.addInitParameter("gateway", "false");
        //客户端应用服务地址
        registration.addInitParameter("serverName", "http://xxx.xxx.xxx.xxx:xxx");
        //此处修改成XX系统新增的跳转页面
        registration.addUrlPatterns("/xxx/xxx");
        return registration;
    }
  1. 修改 AuthenticationFilterLoginSetSession 适配单点登录流程
  • 页面请求业务系统时,AuthenticationFilter 判断session中是否有登陆用户,如果有则执行正常业务流程,如果没有,则跳转到CAS服务器验证登录,
  • CAS服务器验证后,将请求重定向到业务系统,并附带返回票根信息(ticket
  • 业务系统收到请求后,使用Cas20ProxyReceivingTicketValidationFilter先验证对票根信息进行验证是否是有效服务目录返回的,无误后放行进入ClientFilter处理
  • ClientFilter接收到ticket后,再次请求CAS服务器,通过ticket,获取用户的身份识别码并在本地将对应识别码的用户加载到session中,完成登录

上述流程适配过程中出现一个非常诡异的问题,第一次单点登录时,业务系统在使用Cas20ProxyReceivingTicketValidationFilter校验ticket时,会报一个票根'ST-xxxxxx-cas'不符合目标服务”的错误,再次刷新页面(第二次访问触发单点流程)一切正常。
这个错误一般都是由于业务系统配置地址与实际访问地址不符时才会出现,但确认配置没有问题。最后发现是我们的springboot业务系统在配置文件里对session使用的cookie名字进行定制造成的,取消这个配置,单点登录就恢复正常。

session:
    cookie:
      name: xxx-xxx-sessionid

初步猜测单点登录是依赖浏览器端的cookie来维持跨系统的登录状态,使用的是默认jsession,如果被重新定义名称的话,回调时session解析出了问题。

你可能感兴趣的:(springboot 适配CAS单点登录)