zoukankan      html  css  js  c++  java
  • 【试水CAS-4.0.3】第07节_CASclient配置单点登录

    完整版见https://jadyer.github.io/2015/07/26/sso-cas-client-login/




    本文源代码下载:http://download.csdn.net/detail/jadyer/8934207

    /**
     * @see CAS客户端配置
     * @see ------------------------------------------------------------------------------------------------------------------------
     * @see 这里用的是cas-client-core-3.4.0.jar(这是2015-07-21公布的)
     * @see 下载地址http://mvnrepository.com/artifact/org.jasig.cas.client/cas-client-core/3.4.0
     * @see 另外为了使客户端在HTTP协议下单点成功,能够改动以下两处配置使其不开启HTTPS验证
     * @see 1.WEB-INFdeployerConfigContext.xml
     * @see   <bean class="org.jasig...support.HttpBasedServiceCredentialsAuthenticationHandler">加入p:requireSecure="false"
     * @see 2.WEB-INFspring-configuration	icketGrantingTicketCookieGenerator.xml和WEB-INFspring-configurationwarnCookieGenerator.xml
     * @see   p:cookieSecure="true"改为p:cookieSecure="false"
     * @see 以下介绍两种配置方法,一种是纯web.xml配置,一种是借助Spring来配置,相关的官方文档例如以下所看到的
     * @see https://wiki.jasig.org/display/CASC/Configuring+the+Jasig+CAS+Client+for+Java+in+the+web.xml
     * @see https://wiki.jasig.org/display/CASC/Configuring+the+JA-SIG+CAS+Client+for+Java+using+Spring
     * @see ------------------------------------------------------------------------------------------------------------------------
     * @see 纯web.xml
     * @see web.xml中需配置四个顺序固定的Filter,并且出于认证考虑,最好配置在其他Filter之前,它们的先后顺序例如以下
     * @see AuthenticationFilter
     * @see TicketValidationFilter(或其他AbstractTicketValidationFilter实现,比方Cas20ProxyReceivingTicketValidationFilter)
     * @see HttpServletRequestWrapperFilter
     * @see AssertionThreadLocalFilter
     * @see 另外各个Filter的<init-param>优先级都比<context-param>要高,通常<context-param>用来配置公用的參数
     * @see 1.AuthenticationFilter
     * @see   用来拦截请求,推断是否须要CASServer认证,须要则跳转到CASServer登录页,否则放行请求
     * @see   有两个必须參数,一个是指定CASServer登录地址的casServerLoginUrl,还有一个是指定认证成功后跳转地址的serverName或service
     * @see   service和serverName设置一个就可以,二者都设置时service的优先级更高,即会以service为准
     * @see   service指的是一个确切的URL,而serverName是用来指定客户端的主机名的,格式为{protocol}:{hostName}:{port}
     * @see   指定serverName时,该Filter会把它附加上当前请求的URI及相应的查询參数来构造一个确切的URL作为认证成功后的跳转地址
     * @see   比方serverName为"http://gg.cn",当前请求的URI为"/oa",查询參数为"aa=bb",则认证成功后跳转地址为http://gg.cn/oa?

    aa=bb * @see casServerLoginUrl--去哪登录,serverName--我是谁 * @see 2.TicketValidationFilter * @see 请求通过AuthenticationFilter认证后,若请求中携带了ticket參数,则会由该类Filter对携带的ticket进行校验 * @see 验证ticket的时候,要訪问CAS服务的/serviceValidate接口,使用的url就是${casServerUrlPrefix}/serviceValidate * @see 所以它也有两个參数是必须指定的,casServerUrlPrefix(CASServer相应URL地址的前缀)和serverName或service * @see 实际上,TicketValidationFilter仅仅是对验证ticket的这一类Filter的统称,其并不正确应CASClient中的详细类型 * @see CASClient中有多种验证ticket的Filter,都继承自AbstractTicketValidationFilter * @see 常见的有Cas10TicketValidationFilter/Cas20ProxyReceivingTicketValidationFilter/Saml11TicketValidationFilter * @see 它们的验证逻辑都是一致的,都有AbstractTicketValidationFilter实现,仅仅是使用的TicketValidator不一样而已 * @see 假设要从服务器获取username之外的很多其他信息应该採用CAS20这个2.0协议的代理 * @see 3.HttpServletRequestWrapperFilter * @see 用于封装每一个请求的HttpServletRequest为其内部定义的CasHttpServletRequestWrapper * @see 它会将保存在Session或request中的Assertion对象重写HttpServletRequest的getUserPrincipal()、getRemoteUser()、isUserInRole() * @see 这样在我们的应用中就能够很方便的从HttpServletRequest中获取到用户的相关信息 * @see 4.AssertionThreadLocalFilter * @see 为了方便用户在应用的其他地方获取Assertion对象,其会将当前的Assertion对象存放到当前的线程变量中 * @see 以后用户在程序的不论什么地方都能够从线程变量中获取当前的Assertion,而无需从Session或request中解析 * @see 该线程变量是由AssertionHolder持有的,我们在获取当前的Assertion时也仅仅需Assertion assertion = AssertionHolder.getAssertion() * @see ------------------------------------------------------------------------------------------------------------------------ * @see 借助Spring * @see 与上述web.xml配置四个Filter方式不同的是,能够使用Spring的四个DelegatingFilterProxy来代理须要配置的四个Filter * @see 此时这四个Filter就应该配置为Spring的Bean对象,并且web.xml中的<filter-name>就应该相应SpringBean名称 * @see 可是SingleSignOutFilter/HttpServletRequestWrapperFilter/AssertionThreadLocalFilter等Filter不含配置參数 * @see 所以实际上仅仅须要配置AuthenticationFilter和Cas20ProxyReceivingTicketValidationFilter两个Filter交由Spring代理就能够了 * @see ------------------------------------------------------------------------------------------------------------------------ * @see 注意 * @see 1.CAS1.0提供的接口有/validate。CAS2.0提供的接口有/serviceValidate,/proxyValidate,/proxy * @see 2.四个Filter太多了,有时间的话考虑參考org.springframework.web.filter.CompositeFilter写一个Filter来实现 * @see 3.web.xml的优点是能够配置匿名訪问的资源,配置參数參考AuthenticationFilter中的ignoreUrlPatternMatcherStrategyClass * @see 起码cas-client-core-3.4.0.jar中的Spring配置还不支持ignorePattern(该參数默认正则验证,此外还有contains和equals验证) * @see 4.javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching casserver found * @see 这是因为创建证书的域名和应用中配置的CAS服务域名不一致导致出错(说白了就是指客户端导入的CRT证书与CAS服务端的域名不同) * @see ------------------------------------------------------------------------------------------------------------------------ * @create 2015-7-26 下午1:00:14 * @author 玄玉<http://blog.csdn.net/jadyer> */

    以下是web.xml的配置

    <?

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

    > <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>SpringMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>SpringMVC</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <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> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- SSO --> <filter> <filter-name>casAuthenticationFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>casAuthenticationFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter> <filter-name>casTicketValidationFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>casTicketValidationFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- <context-param> <param-name>serverName</param-name> <param-value>http://boss.jadyer.com:8080</param-value> </context-param> <filter> <filter-name>casAuthenticationFilter</filter-name> <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class> <init-param> <param-name>casServerLoginUrl</param-name> <param-value>http://sso.jadyer.com:8080/cas-server-web/login</param-value> </init-param> </filter> <filter-mapping> <filter-name>casAuthenticationFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter> <filter-name>casTicketValidationFilter</filter-name> <filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class> <init-param> <param-name>casServerUrlPrefix</param-name> <param-value>http://sso.jadyer.com:8080/cas-server-web</param-value> </init-param> </filter> <filter-mapping> <filter-name>casTicketValidationFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> --> <filter> <filter-name>casHttpServletRequestWrapperFilter</filter-name> <filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class> </filter> <filter-mapping> <filter-name>casHttpServletRequestWrapperFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter> <filter-name>casAssertionThreadLocalFilter</filter-name> <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class> </filter> <filter-mapping> <filter-name>casAssertionThreadLocalFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>

    以下是//src//applicationContext.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:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd"> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/> <property name="ignoreResourceNotFound" value="false"/> <property name="locations"> <list> <value>classpath:config.properties</value> </list> </property> </bean> <mvc:resources mapping="/index.jsp" location="/index.jsp"/> <!-- cas --> <bean name="casAuthenticationFilter" class="org.jasig.cas.client.authentication.AuthenticationFilter"> <property name="serverName" value="${casClientServerName}"/> <property name="casServerLoginUrl" value="${casServerLoginUrl}"/> </bean> <bean name="casTicketValidationFilter" class="org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter"> <property name="serverName" value="${casClientServerName}"/> <property name="ticketValidator"> <bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator"> <constructor-arg index="0" value="${casServerUrlPrefix}"/> </bean> </property> </bean> </beans>

    以下是//src//config.properties
    #<<Central Authentication Service>>
    #where to login
    casServerLoginUrl=http://sso.jadyer.com:8080/cas-server-web/login
    #login server root
    casServerUrlPrefix=http://sso.jadyer.com:8080/cas-server-web
    #who am i
    #casClientServerName=http://boss.jadyer.com:8180
    casClientServerName=http://risk.jadyer.com:8280
    最后是//WebRoot//index.jsp
    <%@ page pageEncoding="UTF-8"%>
    <%@ page import="java.util.Map"%>
    <%@ page import="java.net.URLDecoder"%>
    <%@ page import="org.jasig.cas.client.util.AssertionHolder"%>
    <%@ page import="org.jasig.cas.client.authentication.AttributePrincipal"%>
    
    <body style="background-color:#CBE0C9;">
    	<span style="color:red; font-size:32px; font-weight:bold;">客户端登录成功</span>
    </body>
    
    <hr size="2">
    
    <%
    	AttributePrincipal principal = (AttributePrincipal)request.getUserPrincipal();
    	Map<String, Object> attributes = principal.getAttributes();
    	out.print("principal.getName()=" + principal.getName() + "<br/>");
    	out.print("request.getRemoteUser()=" + request.getRemoteUser() + "<br/>");
    	out.print("登录用户:" + attributes.get("userId") + "<br/>");
    	out.print("登录时间:" + AssertionHolder.getAssertion().getAuthenticationDate() + "<br/>");
    	out.print("-----------------------------------------------------------------------<br/>");
    	for(Map.Entry<String,Object> entry : attributes.entrySet()){
    		//服务端返回中文时须要encode,客户端接收显示中文时须要decode,否则会乱码
    		out.print(entry.getKey() + "=" + URLDecoder.decode(entry.getValue().toString(), "UTF-8") + "<br/>");
    	}
    	out.print("-----------------------------------------------------------------------<br/>");
    	Map<String, Object> attributes22 = AssertionHolder.getAssertion().getAttributes();
    	for(Map.Entry<String,Object> entry : attributes22.entrySet()){
    		out.print(entry.getKey() + "=" + entry.getValue() + "<br/>");
    	}
    	out.print("-----------------------------------------------------------------------<br/>");
    	Map<String, Object> attributes33 = AssertionHolder.getAssertion().getPrincipal().getAttributes();
    	for(Map.Entry<String,Object> entry : attributes33.entrySet()){
    		out.print(entry.getKey() + "=" + entry.getValue() + "<br/>");
    	}
    %>
    接下来就能够測试了,測试之前先改动几处配置。模拟单点环境
    /**
     * @see ------------------------------------------------------------------------------------------------------------------------
     * @see 測试时在C:WindowsSystem32driversetchosts中加入下面三个配置
     * @see 127.0.0.1 sso.jadyer.com
     * @see 127.0.0.1 boss.jadyer.com
     * @see 127.0.0.1 risk.jadyer.com
     * @see ------------------------------------------------------------------------------------------------------------------------
     * @see 然后拷贝三个Tomcat,分别用作sso服务器和两个ssoclient
     * @see 改动两个ssoclient的Tomcatconfserver.xml的下面三个端口,保证启动监听端口不反复
     * @see <Server port="8105" shutdown="SHUTDOWN">
     * @see <Connector port="8180" protocol="HTTP/1.1"......>
     * @see <Connector port="8109" protocol="AJP/1.3" redirectPort="8443" />
     * @see <Server port="8205" shutdown="SHUTDOWN">
     * @see <Connector port="8280" protocol="HTTP/1.1"......>
     * @see <Connector port="8209" protocol="AJP/1.3" redirectPort="8443" />
     * @see ------------------------------------------------------------------------------------------------------------------------
     * @see 最后改动两个ssoclient的Tomcatwebappscas-clientWEB-INFclassesconfig.properties的casClientServerName值
     * @see casClientServerName=http://boss.jadyer.com:8180
     * @see casClientServerName=http://risk.jadyer.com:8280
     * @see ------------------------------------------------------------------------------------------------------------------------
     * @create 2015-7-26 下午1:08:35
     * @author 玄玉<http://blog.csdn.net/jadyer>
     */

    如今開始測试


    先訪问http://boss.jadyer.com:8180/cas-client,发现没登录会自己主动跳转到单点登录页
    首次訪问当中一个SSOclient


    输入password后登录成功

    SSOclient首次登录成功后的页面效果


    再訪问http://risk.jadyer.com:8280/cas-client,会发现自己主动登录成功,不用再登录了

    第二个SSOclient自己主动登录成功页面

  • 相关阅读:
    VScode快捷键:单行注释和多行注释
    常见状态码的含义
    2019年10月22日 文件操作复习
    2019年10月7日 函数复习
    2019年10月4日 元类
    2019年10月2日 property补充
    2019年10月1日 实现延迟计算功能
    2019年9月30日 property流程分析
    2019年9月29日 自定制property
    2019年9月23日 类的装饰器的应用
  • 原文地址:https://www.cnblogs.com/brucemengbm/p/6991739.html
Copyright © 2011-2022 走看看