JAVA—咖啡馆

——欢迎访问rogerfan的博客,常来《JAVA——咖啡馆》坐坐,喝杯浓香的咖啡,彼此探讨一下JAVA技术,交流工作经验,分享JAVA带来的快乐!本网站部分转载文章,如果有版权问题请与我联系。

BlogJava 首页 新随笔 联系 聚合 管理
  447 Posts :: 145 Stories :: 368 Comments :: 0 Trackbacks

一、概述

单点登录(Single Sign On , 简称 SSO )是目前比较流行的服务于企业业务整合的解决方案之一, SSO 使得在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。CAS(Central Authentication Service)是一款不错的针对 Web 应用的单点登录框架,本文介绍了 CAS 的原理、协议、在 Tomcat 中的配置和使用,对于采用 CAS 实现轻量级单点登录解决方案的入门读者具有一定指导作用。

 

二、CAS介绍

CAS 是 Yale 大学发起的一个开源项目,旨在为 Web 应用系统提供一种可靠的单点登录方法,CAS 在 2004 年 12 月正式成为 JA-SIG 的一个项目(http://www.jasig.org)。CAS 具有以下特点:

1)开源的企业级单点登录解决方案

2)CAS Server 为需要独立部署的 Web 应用

3)CAS Client 支持非常多的客户端(指Web 应用),包括Java,.Net,PHP,Perl,Ruby 等

 

三、CAS原理及协议

从结构上看,CAS 包含两个部分: CAS Server 和 CAS Client。CAS Server 需要独立部署,主要负责对用户的认证工作;CAS Client 负责处理对客户端受保护资源的访问请求,需要登录时,重定向到 CAS Server。AS 最基本的协议过程:

 

CAS Client 与受保护的客户端应用部署在一起,以 Filter 方式保护受保护的资源。对于访问受保护资源的每个 Web 请求,CAS Client 会分析该请求的 Http 请求中是否包含 Service Ticket,如果没有,则说明当前用户尚未登录,于是将请求重定向到指定好的 CAS Server 登录地址,并传递 Service (也就是要访问的目的资源地址),以便登录成功过后转回该地址。用户在第 3 步中输入认证信息,如果登录成功,CAS Server 随机产生一个相当长度、唯一、不可伪造的 Service Ticket,并缓存以待将来验证,之后系统自动重定向到 Service 所在地址,并为客户端浏览器设置一个 Ticket Granted Cookie(TGC),CAS Client 在拿到 Service 和新产生的 Ticket 过后,在第 5,6 步中与 CAS Server 进行身份合适,以确保 Service Ticket 的合法性。

 

在该协议中,所有与 CAS 的交互均采用 SSL 协议,确保,ST 和 TGC 的安全性。协议工作过程中会有 2 次重定向的过程,但是 CAS Client 与 CAS Server 之间进行 Ticket 验证的过程对于用户是透明的。

 

另外,CAS 协议中还提供了 Proxy (代理)模式,以适应更加高级、复杂的应用场景,具体介绍可以参考 CAS 官方网站上的相关文档。

 

四、CAS SERVER配置

1.准备工作

安装配置JDK、安装Tomcat7,此处不做详解。

到CAS官网下载CAS Server和Client,地址如下:

http://downloads.jasig.org/cas/cas-server-4.0.0-release.zip

http://downloads.jasig.org/cas-clients/cas-client-3.2.1-release.zip

 

2.部署

1.将下载的cas-server-4.0.0-release.zip解开,把cas-server-4.0.0/modules/cas-server-webapp-4.0.0.war拷贝到 tomcat的webapps目录,并更名为cas.war。

2.修改cas\WEB-INF\spring-configuration\ticketGrantingTicketCookieGenerator.xml文件,将属性p:cookieSecure="true" 变成 p:cookieSecure="false"(这个设置主要是让CAS不走SSL协议,详见:让CAS不用SSL也可实现跨域)

3.启动tomcat,然后访问:http://localhost:8888/cas,如果能出现正常的CAS登录页面,则说明CAS Server 已经部署成功。如下图:

 

虽然 CAS Server 已经部署成功,但这只是一个缺省的实现,在实际使用的时候,还需要根据实际概况做扩展和定制,最主要的是扩展认证 (Authentication) 接口和 CAS Server 的界面。

 

五、CAS Client配置

将下载的cas-client-3.2.1-release.zip解开,将cas-client-3.2.1/modules/

cas-client-core-3.2.1.jar,放入你的web项目lib目录中,修改web.xml,添加如下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">
    
<display-name>CasClientOne</display-name>
    
<welcome-file-list>
        
<welcome-file>index.html</welcome-file>
        
<welcome-file>index.htm</welcome-file>
        
<welcome-file>index.jsp</welcome-file>
        
<welcome-file>default.html</welcome-file>
        
<welcome-file>default.htm</welcome-file>
        
<welcome-file>default.jsp</welcome-file>
    
</welcome-file-list>
    
    
<!-- ======================== 单点登录结束 ======================== -->
    
<!-- 用于单点退出,该过滤器用于实现单点登出功能,可选配置 -->
    
<listener>
        
<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
    
</listener>
    
    
<!-- 该过滤器用于实现单点登出功能,可选配置。 -->
    
<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>CASFilter</filter-name>
        
<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
        
<init-param>
            
<param-name>casServerLoginUrl</param-name>
            
<param-value>http://localhost:8888/cas/login</param-value><!-- cas 服务器登录 地址  http://IP:PORT/CasWebProName/login -->
        
</init-param>
        
<init-param>
            
<!-- 这里的server是服务端的IP -->
            
<param-name>serverName</param-name>
            
<param-value>http://localhost:8080</param-value><!-- 客户端服务器地址   http://IP:PORT -->
        
</init-param>
    
</filter>

    
<filter-mapping>
        
<filter-name>CASFilter</filter-name>
        
<url-pattern>/*</url-pattern>
    
</filter-mapping>
    
    
<!-- 该过滤器负责对Ticket的校验工作,必须启用它 -->
    
<filter>
        
<filter-name>CAS Validation Filter</filter-name>
        
<filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
        
<init-param>
            
<param-name>casServerUrlPrefix</param-name>
            
<param-value>http://localhost:8888/cas</param-value><!-- cas 服务器地址  http://IP:PORT/CasWebProName -->
        
</init-param>
        
<init-param>
            
<param-name>serverName</param-name>
            
<param-value>http://localhost:8080</param-value><!-- 客户端服务器地址   http://IP:PORT -->
        
</init-param>
    
</filter>
    
<filter-mapping>
        
<filter-name>CAS Validation Filter</filter-name>
        
<url-pattern>/*</url-pattern>
    
</filter-mapping>
    
    
<!-- 该过滤器负责实现HttpServletRequest请求的包裹, 比如允许开发者通过HttpServletRequest的getRemoteUser()方法获得SSO登录用户的登录名,可选配置。 -->
    
<filter>
        
<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
        
<filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
    
</filter>
    
<filter-mapping>
        
<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
        
<url-pattern>/*</url-pattern>
    
</filter-mapping>
    
    
<!-- 该过滤器使得开发者可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。 比如AssertionHolder.getAssertion().getPrincipal().getName()。 -->
    
<filter>
        
<filter-name>CAS Assertion Thread Local Filter</filter-name>
        
<filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
    
</filter>
    
<filter-mapping>
        
<filter-name>CAS Assertion Thread Local Filter</filter-name>
        
<url-pattern>/*</url-pattern>
    
</filter-mapping>
    
<!-- ======================== 单点登录结束 ======================== -->
</web-app>

 

配置完毕后,启动tomcat,然后访问:http://IP:PORT/WebProName/index.jsp,如果系统跳转到CAS登录页面,输入用户名/密码(正确的)后,会跳转到http://IP:PORT/WebProName/index.jsp,则说明CAS Client已经部署成功。

 

注:到此CAS框架已搭建完毕,此种方法未采用SSL协议(需要修改Cas),如果想采用SSL协议方式,则在上述配置中需要以下调整:

  • 修改Cas Server所处Web容器(本文为Tomcat),使其支持SSL协议
  • Cas Server部署时,不需要修改cas\WEB-INF\spring-configuration\ticketGrantingTicketCookieGenerator.xm
  • Cas Client  web.xml中配置的Cas Server相关地址需要将http变更成https

六、JDBC认证方式

1.相关JAR包准备 

cas-server-4.0.0-release.zip\cas-server-4.0.0\modules\cas-server-support-jdbc-4.0.0.jar及相应的数据库驱动包(这里是MySQL驱动mysql-connector-java-5.1.7-bin.jar)复制到cas/WEB-INF/lib目录下。

 

2.修改deployerConfigContext.xml1. 

       <!-- 注释掉原本固定登录用户 -->

<!--     <bean id="primaryAuthenticationHandler" -->

<!--           class="org.jasig.cas.authentication.AcceptUsersAuthenticationHandler"> -->

<!--         <property name="users"> -->

<!--             <map> -->

<!--                 <entry key="casuser" value="Mellon"/> -->

<!--             </map> -->

<!--         </property> -->

<!--     </bean> -->

 

<!-- 变更为JDBC验证方式 -->

    <bean id="primaryAuthenticationHandler" class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">

    <property name="dataSource" ref="dataSource"></property>

    <property name="sql" value="select password from user where user_name=?"></property>

    <property name="passwordEncoder" ref="MD5PasswordEncoder"></property>

    </bean>

 

<!-- 数据源配置 -->

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">

<property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>

<property name="url"><value>jdbc:mysql://localhost:3309/ossm?characterEncoding=utf8</value></property>

<property name="username"><value>root</value></property>

<property name="password"><value>root</value></property> 

</bean> 

 

<!-- 添加MD5密码加密功能 -->

<bean id="MD5PasswordEncoder" class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder">

<constructor-arg index="0">

<value>MD5</value>

</constructor-arg> 

</bean> 

 

七、客户端获取用户登录信息

CAS登录成功默认返回的只有用户名,

JAVA客户端获取:

AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal(); 

String username = principal.getName(); 

 

而在实际应用中,客户端需要知道更多的用户信息,比如用户的性别,年龄,爱好,地址,用户的分组,角色信息等等,下面介绍如何给客户端返回更多的用户资料和信息:

1.修改cas/WEB-INF/deployerConfigContext.xml,注释掉原有的attributeRepository及attributeRepository的引用信息,添加如下信息:

<bean id="attributeRepository" class="org.jasig.services.persondir.support.jdbc.SingleRowJdbcPersonAttributeDao">

        <constructor-arg index="0" ref="dataSource"/>

        <constructor-arg index="1" value="select * from user where {0}"/> 

<!--         <constructor-arg index="1" value="select * from user where {0} {1}"/> -->

        <!-- 组装sql用的查询条件属性 -->

        <property name="queryAttributeMapping">

            <map>

                <!-- 这里的key需写username,value对应数据库用户名字段 -->

                <entry key="username" value="user_name"/>

                <!-- <entry key="id" value="id"/> -->

            </map>

        </property>

        <!-- 如果要组装多个查询条件,需要加上下面这个,默认为AND -->  

        <property name="queryType">

         <value>OR</value>

        </property>  

        <!-- 要获取的属性在这里配置 -->

        <property name="resultAttributeMapping">

            <map>

             <!--key为对应的数据库字段名称,value为提供给客户端获取的属性名字,系统会自动填充值-->

                <entry key="id" value="id"/>

                <entry key="user_name" value="username"/>

                <entry key="phone" value="phone"/>

                <entry key="email" value="email"/>

            </map>

        </property>

    </bean>

 

2.修改cas/WEB-INF/view/jsp/protocol/2.0/casServiceValidationSuccess.jsp,添加下方标红部分:1. 

<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>

<cas:authenticationSuccess>

<cas:user>${fn:escapeXml(assertion.primaryAuthentication.principal.id)}</cas:user>

 

<%-- 返回更多用户信息配置  By Goma --%>

<c:if test="${fn:length(assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.attributes) > 0}">

            <cas:attributes>

                <c:forEach var="attr" items="${assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.attributes}">

                    <cas:${fn:escapeXml(attr.key)}>${fn:escapeXml(attr.value)}</cas:${fn:escapeXml(attr.key)}>

                </c:forEach>

            </cas:attributes>

        </c:if>

 

        <c:if test="${not empty pgtIou}">

        <cas:proxyGrantingTicket>${pgtIou}</cas:proxyGrantingTicket>

        </c:if>

        <c:if test="${fn:length(assertion.chainedAuthentications) > 1}">

  <cas:proxies>

            <c:forEach var="proxy" items="${assertion.chainedAuthentications}" varStatus="loopStatus" begin="0" end="${fn:length(assertion.chainedAuthentications)-2}" step="1">

     <cas:proxy>${fn:escapeXml(proxy.principal.id)}</cas:proxy>

            </c:forEach>

  </cas:proxies>

        </c:if>

</cas:authenticationSuccess>

</cas:serviceResponse>

 

3.客户端取值3. 

AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal(); 

String username = principal.getName(); 

 

Map<String,Object> attributes = principal.getAttributes();

String email = attributes .get("email") + "";

 

八、界面定制

CAS 提供了一套默认的页面,在目录cas/WEB-INF/view/jsp/default下。在部署 CAS 之前,我们可能需要定制一套新的CAS Server页面,添加一些个性化的内容。最简单的方法就是拷贝一份 default文件到“ cas/WEB-INF/view/jsp ”目录下,比如命名为newUI,接下来是实现和修改必要的页面,有 4 个页面是必须的:

casConfirmView.jsp: 当用户选择了“warn”时会看到的确认界面

casGenericSuccess.jsp: 在用户成功通过认证而没有目的Service时会看到的界面

casLoginView.jsp: 当需要用户提供认证信息时会出现的界面

casLogoutView.jsp: 当用户结束 CAS 单点登录系统会话时出现的界面

CAS 的页面采用 Spring框架编写,对于不熟悉 Spring 的使用者,在修改之前需要熟悉该框架。

页面定制完过后,还需要做一些配置从而让 CAS 找到新的页面,拷贝cas/WEB-INF/classes/default_views.properties,重命名为as/WEB-INF/classes/ newUI_views.properties,并修改其中所有的值到相应新页面。最后是更新cas/WEB-INF/cas-servlet.xml文件中的 viewResolver,将protocol_views更改为newUI_views。

 

九、其他功能扩展

增加验证码、密码有效期、限制用户登录之类的功能这里不做描述,如果需要请自行查找。

 


posted on 2016-06-08 10:03 rogerfan 阅读(424) 评论(0)  编辑  收藏 所属分类: 【开源技术】

只有注册用户登录后才能发表评论。


网站导航: