CAS單點登陸實踐(spring cas client配置)

前言:html

  最近的項目須要將多個站點統一登陸,查閱了資料Jasig cas(Central Authentication Service)(官方站點:http://www.jasig.org/cas)使用的比較多。java

項目狀況:web

  開發語言:JAVAspring

  框架:springdocker

  容器:tomcat7api

  JDK: 1.7spring-mvc

  部署方式:dockertomcat

目標:服務器

  實現OMS、BMS、UMS、VOD、Live多站點切換期間只有第一次訪問的站點須要登陸,登陸後調轉的其餘站點不須要在登陸。session

過程:

  在配置前須要開啓tomcat的TLS功能,服務器端和客戶端都要開啓。(切記要講證書導入jre中,遇到 IO.Exception時,能夠將cacerts文件刪除)。網上有些教程爲了簡化操做,使用了http,沒有使用https。可是在http協議下,第一個站點登陸後,第一次跳轉到其餘站點仍是須要再次登陸的。能夠先用http搭建簡單的cas服務器,單個網站能夠調轉過來後,再啓用https。畢竟登陸一次,處處訪問纔是咱們用cas的目的。

一、cas服務器端,參考站點《http://www.cnblogs.com/vhua/p/cas_1.html》

  1.1 解壓下載的 cas-server-4.0.0-release.zip 壓縮包

  1.2 找到 X:\cas-server-4.0.0\modules\cas-server-webapp-4.0.0.war 文件

  1.3解壓到 tomcat-cas\webapps\ 下

  

二、客戶端站點配置:

  2.1 修改web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <listener>
    <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
  </listener>
  <display-name>vod_console</display-name>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value> classpath:config/spring-mybatis.xml,classpath:config/spring-cas.xml </param-value>
    <!-- classpath:config/spring-security.xml -->
  </context-param>
  <context-param>
    <param-name>webAppRootKey</param-name>
    <param-value>vod_console.root</param-value>
  </context-param>
  <context-param>
        <param-name>spring.profiles.active</param-name>  
        <param-value>dev</param-value>  
    </context-param>  
    <context-param>  
        <param-name>spring.profiles.default</param-name>  
        <param-value>dev</param-value>  
    </context-param>
    <context-param>  
        <param-name>spring.liveBeansView.mbeanDomain</param-name>  
        <param-value>dev</param-value>  
    </context-param>
    <!-- 必定要在cas的前面 -->
    <filter>
    <filter-name>SetCharacterEncoding</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>SetCharacterEncoding</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  
     <!-- 單點登陸開始 -->
 <filter>
       <filter-name>CAS Single Sign Out Filter</filter-name>
       <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
    </filter>
 
    <filter-mapping>
       <filter-name>CAS Single Sign Out Filter</filter-name>
       <url-pattern>/*</url-pattern>
    </filter-mapping>
 
 <!-- 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 -->
    <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>
  <servlet>
    <servlet-name>spring</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:config/spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>spring</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
  <error-page>
    <error-code>403</error-code>
    <location>/403</location>
  </error-page>
  <error-page>
    <error-code>404</error-code>
    <location>/404</location>
  </error-page>
  <error-page>
    <error-code>500</error-code>
    <location>/500</location>
  </error-page>
  <listener>
    <listener-class>com.guttv.common.utils.ParamLoaderListener</listener-class>
  </listener>
</web-app>

  注意:原來spring的字符過濾器,必定要在cas的過濾器後面,不然提交數據會出現中文亂碼。這裏參考了「next_door_body」的文章,《http://www.cnblogs.com/next-door-boy/p/3361328.html》,這裏感謝next_door_body。

  2.2 建立spring-cas.xml文件,這個是參考了網站《https://wiki.jasig.org/display/casc/using+the+cas+client+3.1+with+spring+security》

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:sec="http://www.springframework.org/schema/security" 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-3.2.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
    
    <bean id="propertyConfigurer2" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="order" value="2" />
        <property name="ignoreUnresolvablePlaceholders" value="true" />
        <property name="locations">
            <list>
                <value>classpath:config/jdbc.properties</value>
                <value>classpath:config/cas.properties</value>
            </list>
        </property>
    </bean>
    <bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
        <sec:filter-chain-map path-type="ant">
            <sec:filter-chain pattern="/" filters="casValidationFilter, wrappingFilter" />
            <sec:filter-chain pattern="/guttv" filters="casValidationFilter" />
            <sec:filter-chain pattern="/j_spring_security_logout" filters="logoutFilter,etf,fsi" />
            <sec:filter-chain pattern="/**" filters="casAuthenticationFilter, casValidationFilter, wrappingFilter, sif,j2eePreAuthFilter,logoutFilter,etf,fsi" />
        </sec:filter-chain-map>
    </bean>

    <bean id="sif" class="org.springframework.security.web.context.SecurityContextPersistenceFilter" />


    <sec:authentication-manager alias="authenticationManager">
        <sec:authentication-provider ref="preAuthAuthProvider" />
    </sec:authentication-manager>

    <bean id="preAuthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
        <property name="preAuthenticatedUserDetailsService">
            <bean id="userDetailsServiceWrapper" class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
                <property name="userDetailsService" ref="userService" />
            </bean>
        </property>
    </bean>

    <bean id="preAuthEntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint" />

    <bean id="j2eePreAuthFilter" class="org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter">
        <property name="authenticationManager" ref="authenticationManager" />
        <property name="authenticationDetailsSource">
            <bean class="org.springframework.security.web.authentication.WebAuthenticationDetailsSource" />
        </property>
    </bean>

    <bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
        <constructor-arg value="/" />
        <constructor-arg>
            <list>
                <bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" />
            </list>
        </constructor-arg>
    </bean>

    <bean id="servletContext" class="org.springframework.web.context.support.ServletContextFactoryBean" />

    <bean id="etf" class="org.springframework.security.web.access.ExceptionTranslationFilter">
        <property name="authenticationEntryPoint" ref="preAuthEntryPoint" />
    </bean>

    <bean id="httpRequestAccessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
        <property name="allowIfAllAbstainDecisions" value="false" />
        <property name="decisionVoters">
            <list>
                <ref bean="roleVoter" />
            </list>
        </property>
    </bean>

    <bean id="fsi" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
        <property name="authenticationManager" ref="authenticationManager" />
        <property name="accessDecisionManager" ref="httpRequestAccessDecisionManager" />
        <property name="securityMetadataSource">
            <sec:filter-invocation-definition-source>
                <sec:intercept-url pattern="/secure/extreme/**" access="ROLE_SUPERVISOR" />
                <sec:intercept-url pattern="/combo/**" access="ROLE_USER" />
                <sec:intercept-url pattern="/**" access="ROLE_USER" />
            </sec:filter-invocation-definition-source>
        </property>
    </bean>

    <bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter" />

    <bean id="securityContextHolderAwareRequestFilter" class="org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter" />

    <bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator" id="ticketValidator">
        <constructor-arg index="0" value="${casServer}/cas" />
        <property name="proxyGrantingTicketStorage" ref="proxyGrantingTicketStorage" />
        <property name="proxyCallbackUrl" value="${vod.localServer}/${vod.project}/category/tree/listRoot" />

    </bean>

    <bean id="proxyGrantingTicketStorage" class="org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl" />

    <sec:user-service id="userService">
        <sec:user name="lzj999" password="1234" authorities="ROLE_SUPERVISOR,ROLE_USER" />
        <sec:user name="dianne" password="dianne" authorities="ROLE_USER" />
        <sec:user name="lzj" password="1234" authorities="ROLE_USER" />
    </sec:user-service>

    <bean id="casAuthenticationFilter" class="org.jasig.cas.client.authentication.AuthenticationFilter">
        <property name="casServerLoginUrl" value="${casServer}/cas/login" />
        <property name="serverName" value="${vod.localServer}" />
    </bean>

    <bean id="casValidationFilter" class="org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter">
        <property name="serverName" value="${vod.localServer}" />
        <property name="exceptionOnValidationFailure" value="true" />
        <property name="proxyGrantingTicketStorage" ref="proxyGrantingTicketStorage" />
        <property name="redirectAfterValidation" value="true" />
        <property name="ticketValidator" ref="ticketValidator" />
        <property name="proxyReceptorUrl" value="/guttv" />
    </bean>

    <bean id="wrappingFilter" class="org.jasig.cas.client.util.HttpServletRequestWrapperFilter" />
</beans>

   本文件中的相關參數都被提取到cas.properties文件中了,spring-cas.xml就比較通用了,參數也看得比較清晰。

casServer=https://dev.guttv.com:8443
oms.localServer = https://dev.guttv.com:9443
oms.project = oms_console
vod.localServer = https://dev.guttv.com:9443
vod.project = vod_console

2.3 登陸用戶名的獲取:

  

<%@ page import="org.jasig.cas.client.authentication.AttributePrincipal"%>

<% /*CasAuthenticationToken casAuthenticationToken = (CasAuthenticationToken) SecurityContextHolder .getContext().getAuthentication(); AttributePrincipal principal = casAuthenticationToken .getAssertion().getPrincipal(); request.setAttribute("username", principal.getName()); */ AttributePrincipal principal = (AttributePrincipal) request .getUserPrincipal(); String username = principal.getName(); request.setAttribute("username", username); String password = principal.getProxyTicketFor(username); request.setAttribute("pwd", password); %>

<c:when test="${not empty username }">
                        <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="true">你好:${username } <span class="caret"></span>
                        </a>
                            <ul class="dropdown-menu" role="menu">
                                <li><a href="${context }/user/person">我的信息</a></li>
                                <li class="divider"></li>
                                <li><a href="${context }/static/j_spring_security_logout">退出</a></li>
                            </ul></li>

                    </c:when>

 

org.jasig.cas.client.authentication.AttributePrincipal在cas-client-core-3.2.1.jar包裏,這個包是Jasig提供的。
相關文章
相關標籤/搜索