springsecurity整合cas客户端

springsecurity整合cas客户端

这几天都在弄一个springSecurity整合Cas的单点登陆的例子,cas服务端已经弄好的,所以这里我只是说一下客户端的配置我是怎么弄的,以及出现的问题

  1. web.xml文件
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	id="zhongjiaoyun" version="2.5">
	<display-name>sso test</display-name>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- 解决post乱码 -->
	<filter>
		<filter-name>CharacterEncodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>utf-8</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>CharacterEncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<!-- spring mvc start -->
	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath*:spring/spring-mvc.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			classpath*:spring/spring-mvc.xml
		</param-value>
	</context-param>
	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<url-pattern>/pages/*</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<url-pattern>/hyperlink/*</url-pattern>
	</servlet-mapping>

	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<url-pattern>/rest/*</url-pattern>
	</servlet-mapping>

	<filter>
		<filter-name>HiddenHttpMethodFilter</filter-name>
		<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>HiddenHttpMethodFilter</filter-name>
		<servlet-name>dispatcher</servlet-name>
	</filter-mapping>

	<!-- cas security start -->
	<listener>
		<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
	</listener>
	<filter>
		<filter-name>springSecurityFilterChain</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>springSecurityFilterChain</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	<!-- cas security end -->
	
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
	</welcome-file-list>
	<session-config>
		<session-timeout>30</session-timeout>
	</session-config>
</web-app>

2.接下来是springMVC.xml,里面引入了spring-security-cas.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd   
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 引入配置文件 -->
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
        <property name="locations">
            <list>
                <value>classpath:env.properties</value>
            </list>
        </property>
    </bean>
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="properties" ref="propertyConfigurer"/>
        <property name="order" value="-1"/>
    </bean>


    <!-- 使用Annotation自动注册Bean,只扫描@Controller -->
    <context:component-scan base-package="com.cccc" use-default-filters="false"><!-- base-package 如果多个,用“,”分隔 -->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>


    <!-- 支持返回json(避免IE在ajax请求时,返回json出现下载 ) -->
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
            <list>
                <ref bean="mappingJacksonHttpMessageConverter"/>
            </list>
        </property>
    </bean>
    <bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
        <property name="supportedMediaTypes">
            <list>
                <value>text/plain;charset=UTF-8</value>
                <value>application/json;charset=UTF-8</value>
            </list>
        </property>
        <property name="objectMapper">
            <bean class="com.fasterxml.jackson.databind.ObjectMapper">
                <property name="dateFormat">
                    <bean class="java.text.SimpleDateFormat">
                        <constructor-arg value="yyyy-MM-dd HH:mm:ss"/>
                    </bean>
                </property>
            </bean>
        </property>
    </bean>


    <bean id="mappingJackson2HttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
        <property name="supportedMediaTypes">
            <list>
                <value>text/json;charset=UTF-8</value>
            </list>
        </property>
    </bean>
    <bean id="stringHttpMessageConverter" class="org.springframework.http.converter.StringHttpMessageConverter"/>

    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
            <list>
                <ref bean="mappingJackson2HttpMessageConverter"/>
                <ref bean="stringHttpMessageConverter"/>
            </list>
        </property>
    </bean>
    <!-- 支持返回json -->

    <import resource="classpath*:/spring/spring-security-cas.xml"/>

</beans>

  1. spring-security-cas.xml配置如下:
<beans xmlns="http://www.springframework.org/schema/beans"  
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:security="http://www.springframework.org/schema/security"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">

	<!-- 指定登录入口为casEntryPoint -->
	<security:http entry-point-ref="casEntryPoint" use-expressions="true" >
		<security:intercept-url pattern="/html/**" access="isFullyAuthenticated()"/>
		<security:custom-filter ref="switchUserFilter" before="FILTER_SECURITY_INTERCEPTOR" />
		<!-- 请求登出Cas Server的过滤器,放在Spring Security的登出过滤器之前  -->
		<security:custom-filter ref="requestCasLogoutFilter" before="LOGOUT_FILTER" />
		<!-- SingleSignOutFilter放在CAS_FILTER之前 -->
		<security:custom-filter ref="casLogoutFilter" before="CAS_FILTER" />
		<security:custom-filter ref="casFilter" position="CAS_FILTER" />
	</security:http>

	<!-- 认证的入口 -->
	<bean id="casEntryPoint"
		class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
		<!-- Cas Server的登录地址 -->
		<property name="loginUrl" value="${spring.security.cas.prefix}/login" />
		<!-- service相关的属性 -->
		<property name="serviceProperties" ref="serviceProperties" />
	</bean>

	<bean id="casFilter" class="org.springframework.security.cas.web.CasAuthenticationFilter">
		<property name="authenticationManager" ref="authenticationManager" />
	</bean>

	<security:authentication-manager alias="authenticationManager">
		<security:authentication-provider ref="casAuthenticationProvider" />
	</security:authentication-manager>

	<bean id="casAuthenticationProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
		<!-- 通过username来加载UserDetails -->
		<property name="authenticationUserDetailsService">
			<bean class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
				<!-- 真正加载UserDetails的UserDetailsService实现 -->
				<constructor-arg ref="userInfoService" />
			</bean>
		</property>
		<property name="serviceProperties" ref="serviceProperties" />
		<!-- 配置TicketValidator在登录认证成功后验证ticket -->
		<property name="ticketValidator">
			<bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
				<!-- Cas Server访问地址的前缀,即根路径 -->
				<constructor-arg index="0" value="${spring.security.cas.prefix_intranet}" />
			</bean>
		</property>
		<property name="key" value="key4CasAuthenticationProvider" />
	</bean>

	<!-- 指定service相关信息 -->
	<bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
		<!-- Cas Server认证成功后的跳转地址,这里要跳转到我们的Spring Security应用,之后会由CasAuthenticationFilter处理,默认处理地址为/j_spring_cas_security_check -->
		<property name="service" value="${spring.security.sysmgr.service.prefix}/j_spring_cas_security_check" />
	</bean>

	<bean id="switchUserFilter" class="org.springframework.security.web.authentication.switchuser.SwitchUserFilter">  
	    <property name="userDetailsService" ref="userInfoService"/>  
	    <!-- usernameParameter属性表示传递的用户名称的参数名称 -->
	    <property name="usernameParameter" value="userId"/>
	    <!--targetUrl属性表示切换用户成功后应该转向哪个地址 -->  
	    <property name="targetUrl" value="/switch/success"/>
	    <!--switchUserUrl属性表示SwitchUserFilter拦截的请求地址-->
	    <!--<property name="switchUserUrl" value="/switch"/>--> 
	    <!-- exitUserUrl表示切换用记成功后如果想要退出应该设置的url请求地址 -->
	    <!-- <property name="exitUserUrl" value="/exit"/>   -->
	</bean>

	<bean id="userInfoService" class="com.cccc.security.UserInfoService" lazy-init="true" ></bean>

	<bean id="casLogoutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter" />
	
	<bean id="requestCasLogoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
		<!-- 指定登出成功后需要跳转的地址,这里指向Cas Server的登出URL,以实现单点登出 -->

		<constructor-arg value="${spring.security.cas.prefix}/logout?service=${spring.security.sysmgr.service.login.url}" />
		<constructor-arg>
			<bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" />
		</constructor-arg>
		<!-- 该Filter需要处理的地址,默认是Spring Security的默认登出地址“/j_spring_security_logout” -->
		<property name="filterProcessesUrl" value="/j_spring_cas_security_logout" />
	</bean>
	
</beans>

还有对应的环境配置文件 env.properties

#注意一下,这个地址需要在cas服务端加入到白名单
spring.security.sysmgr.service.prefix=http://localhost:8080/sso_test
spring.security.cas.prefix=https://xxx.xx.com  //cas服务认证地址
spring.security.cas.prefix_intranet=https://xxx.xx.com  //cas服务认证地址和上面一样
spring.security.sysmgr.service.login.url=https://xxx.cxc.cn//这个是退出之后的地址

4,java的实现类
这个实现类里面不用做任何的逻辑处理


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import java.util.HashMap;
import java.util.Map;

public class UserInfoService implements UserDetailsService {
    private final Log logger = LogFactory.getLog(getClass());

    /**
     * 此处的参数[loginId]为CAS登录画面输入的用户名
     */
    @Override
    public UserDetails loadUserByUsername(String loginId) throws UsernameNotFoundException {
        String[] loginIds = loginId.split(",");
        Long loginId1 = Long.valueOf(loginIds[0]);
        logger.info(loginId1);
        System.out.println("ID--->" + loginId1);

        UserInfo userInfo = new UserInfo();
        userInfo.setUid(loginId1);
        userInfo.setUsername("wwd");
        userInfo.setPassword("123456");
        userInfo.setName("wwdname");
        userInfo.setOrgLeafId(111L);
        userInfo.setCompId(11111L);
        userInfo.setDeptId(111112L);
        userInfo.setOrgFullName("test");
        userInfo.setOrgFullName("test");
        userInfo.setDeptName("test");
        userInfo.setIsprofess("test");
        userInfo.setCompName("test");

        return userInfo;
    }
}

到这里基本上就已经配置完毕了,我自己的例子中还是用到了apache的反向代理,就是cas认证服务器白名单中的一个地址代理成我本地的地址,这个网上都是有详细的说明的。就是说到这里吧,弄这个springsecurity整合cas的单点登陆花了我好几天,哎、、、


版权声明:本文为funkMusic原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。