cas4.2.7实现单点登录

简介:

准备前参考: 

 cas server下载地址

 cas client 下载地址

   安全cookie setSecure详解

   Spring通过构造方法注入的四种方式

 cas 学习博文

v自定义登录页和登录认证

  cas server端的login-webflow详细流程

  CAS服务端自定义数据库认证用户

 

v准备工作

  1. cas server下载之后解压,在项目根目录下执行 mvn clean 和 mvn install命令(如果使用给定的命令报错)。

  2. 根目录下会生成target目录,target中会有一个cas.war的文件,将这个文件通过 mvn install 发布到maven的本地仓库中。

  

 

mvn install:install-file -DgroupId=com.hjz -DartifactId=cas -Dversion=1.0.0 -Dfile=cas.war -Dpackaging=war -DgeneratePom=true

 

  3.项目中的依赖

<dependency>
  <groupId>com.hjz</groupId>
  <artifactId>cas</artifactId>
  <version>1.0.0</version>
  <type>war</type>
</dependency>

v客户端cas ticket验证走查

  1.如果请求中携带了参数ticket则将会由TicketValidationFilter来对携带的ticket进行校验。TicketValidationFilter只是对验证ticket的这一类Filter的统称,其并不对应Cas Client中的一个具体类型。Cas Client中有多种验证ticket的Filter,都继承自AbstractTicketValidationFilter,它们的验证逻辑都是一致的,都有AbstractTicketValidationFilter实现,所不同的是使用的TicketValidator不一样。笔者这里将以Cas20TicketValidationFilter为例。

复制代码
<context-param>
      <param-name>serverName</param-name>
      <param-value>http://127.0.0.1:8089</param-value>
</context-param>

<filter>
   <filter-name>casTicketValidationFilter</filter-name>
<filter-class>org.jasig.cas.client.validation.Cas10TicketValidationFilter</filter-class>
   <init-param>
      <param-name>casServerUrlPrefix</param-name>
      <param-value>http://127.0.0.1:8080/cas</param-value>
   </init-param>
</filter>
<filter-mapping>
   <filter-name>casTicketValidationFilter</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>
复制代码

  一个是用来指定Cas Server登录地址的casServerLoginUrl,另一个是用来指定认证成功后需要跳转地址的serverNameservice。service和serverName只需要指定一个就可以了。当两者都指定了,参数service将具有更高的优先级,即将以service指定的参数值为准。service和serverName的区别在于service指定的是一个确定的URL,认证成功后就会确切的跳转到service指定的URL;而serverName则是用来指定主机名,其格式为{protocol}:{hostName}:{port},如:https://localhost:8443,当指定的是serverName时,AuthenticationFilter将会把它附加上当前请求的URI,以及对应的查询参数来构造一个确定的URL,如指定serverName为“http://localhost”,而当前请求的URI为“/app”,查询参数为“a=b&b=c”,则对应认证成功后的跳转地址将为“http://localhost/app?a=b&b=c”。

       必须指定的参数:

   casServerUrlPrefix:用来指定Cas Server对应URL地址的前缀,如上面示例的“https://elim:8443/cas”。

   serverName或service:语义跟前面介绍的一致。

 

       可选参数:

   redirectAfterValidation :表示是否验证通过后重新跳转到该URL,但是不带参数ticket,默认为true。

   useSession :在验证ticket成功后会生成一个Assertion对象,如果useSession为true,则会将该对象存放到Session中。如果为false,则要求每次请求都需要携带ticket进行验证,显然useSession为false跟redirectAfterValidation为true是冲突的。默认为true。

  exceptionOnValidationFailure :表示ticket验证失败后是否需要抛出异常,默认为true。

   renew:当值为true时将发送“renew=true”到Cas Server,默认为false。

  

  2.通过模仿 Cas10TicketValidationFilter 的逻辑,自定义 ticket validation filter。

  View Code

  这样,servername 和 casServerUrlPrefix 获取的逻辑可以自定义了,例如可以放到 .properties 中。

 

  3.通过casServerUrlPrefix 和 Cas10TicketValidator 或(Cas20ProxyTicketValidator)的 getUrlSuffix方法(返回值分别是“validate”和“serviceValidate”)可以确定出 具体的校验ticket的接口。通过查看 cas server的web.xml,可以在servlet-mapping中看到getUrlSuffix返回值对应的servlet是org.springframework.web.servlet.DispatcherServlet,参数contextConfigLocation 对应的值是'/WEB-INF/cas-servlet.xml, /WEB-INF/cas-servlet-*.xml',里面定义了springmvc初始的handlerMapping和handlerAdapter,如下。

复制代码
  <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

  <bean
      id="handlerMappingC"
      class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"
      p:alwaysUseFullPath="true">
    <property name="mappings">
      <util:properties>
        <prop key="/serviceValidate">serviceValidateController</prop>
        <prop key="/proxyValidate">proxyValidateController</prop>

        <prop key="/p3/serviceValidate">v3ServiceValidateController</prop>
        <prop key="/p3/proxyValidate">v3ProxyValidateController</prop>
        <prop key="/validate">legacyValidateController</prop>
        <prop key="/proxy">proxyController</prop>
        <prop key="/authorizationFailure.html">passThroughController</prop>
      </util:properties>
    </property>
  </bean>
复制代码

  找到 '/serviceValidate' 对应的bean -> serviceValidateController

复制代码
   <bean id="abstractValidateController" class="org.jasig.cas.web.ServiceValidateController" abstract="true"
        p:centralAuthenticationService-ref="centralAuthenticationService"
        p:proxyHandler-ref="proxy20Handler"
        p:argumentExtractor-ref="casArgumentExtractor"
        p:servicesManager-ref="servicesManager" />

  <bean id="serviceValidateController" parent="abstractValidateController"
        p:validationSpecificationClass="org.jasig.cas.validation.Cas20WithoutProxyingValidationSpecification"/>
复制代码

  于是可以确认 最终调用 org.jasig.cas.web.ServiceValidateController 进行ticket验证。到底是调用哪个方法呢? 这里先看一下 springmvc中 DispatchServlet的doDispatch方法,如下。

  View Code

  接下来看一下  org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter 的handle方法,如下。

  View Code

  可见,handlerAdapter的handle方法调用了某个具体handler的handleRequest方法,查看如上handler配置中 org.jasig.cas.web.ServiceValidateController 的handleRequest方法,如下。

  View Code

  父类handleRequest方法调用了handleRequestInternal方法,子类ServiceValidateController 自身重写了 handleRequestInternal方法。

  View Code

  handleRequestInternal方法中调用了一个argumentExtractor,在上面的配置中可以看到,可确定这是个 spring bean。这个bean在 WEB-INF/spring-configuration/argumentExtractorsConfiguration.xml中,内容如下。

  View Code

  查看org.jasig.cas.web.support.CasArgumentExtractor内容如下。

  View Code

  最后查看org.jasig.cas.authentication.principal.SimpleWebApplicationServiceImpl内容如下。

  View Code

  在SimpleWebApplicationServiceImpl createServiceFrom方法中可以看到,ticket从request中取到。也就是对应 org.jasig.cas.web.ServiceValidateController 的handleRequestInternal 如下获取方式。

final WebApplicationService service = this.argumentExtractor.extractService(request);
final String serviceTicketId = service != null ? service.getArtifactId() : null;

 

v通过配置deployerConfigContext.xml实现自定义认证(本例中提供了四中方式)

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:sec="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/tx http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <!-- 数据源配置, 使用druid连接池 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
          init-method="init" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driver}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <!-- 配置初始化大小、最小、最大 -->
        <property name="initialSize" value="${druid.initialSize}"/>
        <property name="minIdle" value="${druid.minIdle}"/>
        <property name="maxActive" value="${druid.maxActive}"/>

        <!-- 配置获取连接等待超时的时间 -->
        <property name="maxWait" value="${druid.maxWait}"/>
        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="${druid.timeBetweenEvictionRunsMillis}" />

        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="${druid.minEvictableIdleTimeMillis}" />

        <property name="validationQuery" value="${druid.validationQuery}" />
        <property name="testWhileIdle" value="${druid.testWhileIdle}" />
        <property name="testOnBorrow" value="${druid.testOnBorrow}" />
        <property name="testOnReturn" value="${druid.testOnReturn}" />

        <!-- 打开PSCache,并且指定每个连接上PSCache的大小  如果用Oracle,则把poolPreparedStatements配置为true,mysql可以配置为false。-->
        <property name="poolPreparedStatements" value="${druid.poolPreparedStatements}" />
        <property name="maxPoolPreparedStatementPerConnectionSize" value="${druid.maxPoolPreparedStatementPerConnectionSize}" />
    </bean>

    <bean id="usernamePasswordAuthenticationHandler" class="com.hjzgg.auth.UsernamePasswordAuthenticationHandler"/>

    <util:map id="authenticationHandlersResolvers">
        <entry key-ref="proxyAuthenticationHandler" value-ref="proxyPrincipalResolver" />
        <entry key-ref="primaryAuthenticationHandler" value-ref="primaryPrincipalResolver" />
    </util:map>

    <util:list id="authenticationMetadataPopulators">
        <ref bean="successfulHandlerMetaDataPopulator" />
        <ref bean="rememberMeAuthenticationMetaDataPopulator" />
    </util:list>

    <bean id="attributeRepository" class="org.jasig.services.persondir.support.NamedStubPersonAttributeDao"
          p:backingMap-ref="attrRepoBackingMap" />

    <!--first 默认方式-->
    <!--<alias name="acceptUsersAuthenticationHandler" alias="primaryAuthenticationHandler" />-->

    <!--second 使用 MD5对密码进行加密-->
    <!--<bean id="MD5PasswordEncoder" class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder" autowire="byName">
        <constructor-arg  value="MD5"/>
    </bean >
    <bean id="queryDatabaseAuthenticationHandler" name="primaryAuthenticationHandler" class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">
        <property name="passwordEncoder" ref="MD5PasswordEncoder"/>
    </bean>-->

    <!--third 不使用加密算法-->
    <!--<alias name="queryDatabaseAuthenticationHandler" alias="primaryAuthenticationHandler" />-->

    <!--forth 通过继承AbstractUsernamePasswordAuthenticationHandler,并实现authenticateUsernamePasswordInternal-->
    <alias name="usernamePasswordAuthenticationHandler" alias="primaryAuthenticationHandler" />
    <alias name="personDirectoryPrincipalResolver" alias="primaryPrincipalResolver" />

    <alias name="dataSource" alias="queryDatabaseDataSource" />

    <util:map id="attrRepoBackingMap">
        <entry key="uid" value="uid" />
        <entry key="eduPersonAffiliation" value="eduPersonAffiliation" />
        <entry key="groupMembership" value="groupMembership" />
        <entry>
            <key><value>memberOf</value></key>
            <list>
                <value>faculty</value>
                <value>staff</value>
                <value>org</value>
            </list>
        </entry>
    </util:map>

    <alias name="serviceThemeResolver" alias="themeResolver" />

    <alias name="jsonServiceRegistryDao" alias="serviceRegistryDao" />

    <alias name="defaultTicketRegistry" alias="ticketRegistry" />
    
    <alias name="ticketGrantingTicketExpirationPolicy" alias="grantingTicketExpirationPolicy" />
    <alias name="multiTimeUseOrTimeoutExpirationPolicy" alias="serviceTicketExpirationPolicy" />

    <alias name="anyAuthenticationPolicy" alias="authenticationPolicy" />
    <alias name="acceptAnyAuthenticationPolicyFactory" alias="authenticationPolicyFactory" />

    <bean id="auditTrailManager"
          class="org.jasig.inspektr.audit.support.Slf4jLoggingAuditTrailManager"
          p:entrySeparator="${cas.audit.singleline.separator:|}"
          p:useSingleLine="${cas.audit.singleline:false}"/>

    <alias name="neverThrottle" alias="authenticationThrottle" />

    <util:list id="monitorsList">
        <ref bean="memoryMonitor" />
        <ref bean="sessionMonitor" />
    </util:list>

    <alias name="defaultPrincipalFactory" alias="principalFactory" />
    <alias name="defaultAuthenticationTransactionManager" alias="authenticationTransactionManager" />
    <alias name="defaultPrincipalElectionStrategy" alias="principalElectionStrategy" />
    <alias name="tgcCipherExecutor" alias="defaultCookieCipherExecutor" />
</beans>
复制代码

 

v相关参考

vCAS Properties

vDatabase Authentication

vCAS4.2.x

v报异常:Application Not Authorized to Use CAS

       cas4.2.7 取消https  

vCas https 证书生成

复制代码
keytool -genkey -keyalg RSA -alias cas.server.com -dname "cn=cas.server.com" -keystore /usr/data/tomcat.keystore
 
sudo keytool -export -alias cas.server.com -keystore /usr/data/tomcat.keystore  -file /usr/data/tomcat.cer
 
cd  /Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/security
 
sudo keytool -import -keystore cacerts -file /usr/data/tomcat.cer -alias cas.server.com -storepass changeit
 
 
sudo keytool -delete -trustcacerts -alias cas.server.com -keystore "/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/security/cacerts" -storepass changeit
 
keytool -list -keystore /Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/security/cacerts -storepass changeit 
复制代码

 

完整项目地址:https://github.com/hjzgg/cas4.2.7-authentication

cas4.2.7 template项目地址:https://github.com/hjzgg/cas-overlay-template-4.2.7










本文转自 小眼儿 博客园博客,原文链接:http://www.cnblogs.com/hujunzheng/p/5694933.html,如需转载请自行联系原作者
目录
相关文章
|
安全 Java 应用服务中间件
基于CAS实现SSO单点登录
基于CAS实现SSO单点登录
基于CAS实现SSO单点登录
|
安全 Java 应用服务中间件
基于CAS,实现SSO单点登录,很细
基于CAS,实现SSO单点登录,很细
436 0
基于CAS,实现SSO单点登录,很细
|
NoSQL 前端开发 JavaScript
单点登录和CAS解决方案入门
单点登录和CAS解决方案入门
317 0
单点登录和CAS解决方案入门
|
存储 NoSQL 安全
JavaWeb - SSO单点登录原理之基于CAS(一)
JavaWeb - SSO单点登录原理之基于CAS(一)
215 0
|
缓存 网络安全
JavaWeb - SSO单点登录原理之基于CAS(二)
JavaWeb - SSO单点登录原理之基于CAS(二)
211 0
JavaWeb - SSO单点登录原理之基于CAS(二)
|
存储 SQL 安全
CAS实现单点登录
单点登录(Single Sign On),简称为 SSO,是比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。
263 0
CAS实现单点登录
shiro、cas、pac4j 实现单点登陆(1)
shiro、cas、pac4j 实现单点登陆(1)
186 0
shiro、cas、pac4j 实现单点登陆(1)
shiro、cas、pac4j 实现单点登陆(2)
shiro、cas、pac4j 实现单点登陆(2)
121 0
shiro、cas、pac4j 实现单点登陆(2)
|
安全 算法 Java
使用CAS实现单点登录
使用CAS实现单点登录
266 0
使用CAS实现单点登录
|
Web App开发 安全 Java