• 【试水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自己主动登录成功页面

  • 相关阅读:
    tile38 复制配置
    The Guardian’s Migration from MongoDB to PostgreSQL on Amazon RDS
    tile38 一款开源的geo 数据库
    sqler sql 转rest api 的docker 镜像构建(续)使用源码编译
    sqler sql 转rest api javascript 试用
    sqler sql 转rest api redis 接口使用
    sqler sql 转rest api 的docker image
    sqler sql 转rest api 的工具试用
    apache geode 试用
    benthos v1 的一些新功能
  • 原文地址:https://www.cnblogs.com/brucemengbm/p/6991739.html
Copyright © 2020-2023  润新知