配置环境:
JDK 1.6 + TOMCAT 6
Yale CAS Server3.5.2 + Client3.2.1
工作准备:
到 http://www.jasig.org/cas 中下载对应版本的 服务器端cas-server-3.5.2-release.zip 和 客户端cas-client-3.2.1-release.zip
一、尝试运行CAS服务器端
解压cas-server-3.5.2-release.zip, 在里面的moudles文件夹里有个cas-server-webapp-3.5.2.war文件, 这个就是服务器的所有文件, 解压, 设置tomcat的server.xml把该文件夹添加对应的虚拟目录, 我们以 http://localhost:8080/cas 为例,登录 http://localhost:8080/cas 后你们可以看到登录界面,便于测试,CAS默认输入相同的账号跟密码即可通过登录验证。
二、配置CAS服务端,使其读取mysql数据库对应的数据进行登录判断
打开CAS的/WEB-INF/deployerConfigContext.xml,找到以下代码并注释掉,取消掉原来的用于测试的简单验证
<bean class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePasswordAuthenticationHandler" />
换成以下的验证方式
<bean class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler"> <property name="dataSource" ref="dataSource" /> <property name="sql" value="SELECT password FROM account WHERE email=?" /> </bean>
并配置对应的数据源(添加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:3306/sway_account?useUnicode=true&characterEncoding=utf-8</value> </property> <property name="username"> <value>root</value> </property> <property name="password"> <value></value> </property> </bean>
三、配置CAS客户端
新建一个tomcat虚拟目录,我们以 http://localhost:8080/test 为例,并且确保里面有一个可访问的文件(我们这里以index.jsp为例),解压cas-client-3.2.1-release.zip,在里面modules里面找到cas-client-core-3.2.1.jar以及commons-logging-1.1.jar文件,复制到 http://localhost:8080/test 项目里面的 WEB-INF/lib 文件夹里面,然后修改里面的web.xml文件,添加以下过滤器:
<?xml version="1.0" encoding="UTF-8"?> <web-app id="WebApp_ID" version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <welcome-file-list> <welcome-file>index.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:8080/cas/login</param-value> <!--这里的server是服务端的IP --> </init-param> <init-param> <param-name>serverName</param-name> <param-value>http://localhost:8080/</param-value> </init-param> </filter> <filter-mapping> <filter-name>CASFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 该过滤器负责对Ticket的校验工作,必须启用它 --> <!-- ValidationFilter 这个filter负责对请求参数ticket进行验证(ticket参数是负责子系统与CAS进行验证交互的凭证)casServerUrlPrefix:CAS服务访问地址serverName:当前应用所在的主机名 --> <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:8080/cas</param-value> </init-param> <init-param> <param-name>serverName</param-name> <param-value>http://localhost:8080/</param-value> </init-param> </filter> <filter-mapping> <filter-name>CAS Validation Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 3.(可选)HttpServletRequestWrapperFilter 这个是HttpServletRequet的包裹类,让他支持getUserPrincipal,getRemoteUser方法来取得用户信息 --> <!-- 该过滤器负责实现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> <!-- 4.(可选)AssertionThreadLocalFilter 这个类把Assertion信息放在ThreadLocal变量中,这样应用程序不在web层也能够获取到当前登录信息 Assertion assersion =AssertionHolder.getAssertion(); --> <!--该过滤器使得开发者可以通过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>
四、读取更多的客户端信息
打开CAS的/WEB-INF/deployerConfigContext.xml,
找到bean id为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 account where {0}</value> </constructor-arg> <!-- 组装sql用的查询条件属性 --> <property name="queryAttributeMapping"> <map> <entry key="username" value="email" /> <!-- <entry key="username" value="userAccount" /> --> </map> </property> <!-- 如果要组装多个查询条件,需要加上下面这个,默认为AND --> <!-- <property name="queryType"> <value>OR</value> </property> --> <!-- 要获取的属性在这里配置 --> <property name="resultAttributeMapping"> <map> <!--key为对应的数据库字段名称,value为提供给客户端获取的属性名字,系统会自动填充值 --> <entry key="id" value="id" /> <entry key="email" value="email" /> <entry key="emailValidated" value="emailValidated" /> <entry key="password" value="password" /> <entry key="registerTime" value="registerTime" /> <entry key="lastLoginTime" value="lastLoginTime" /> <entry key="balance" value="balance" /> </map> </property> </bean>
修改该xml文件中最后一个默认的serviceRegistryDao bean,找到<bean class=”org.jasig.cas.services.RegexRegisteredService”>把高亮部分添加进去:
<bean class="org.jasig.cas.services.RegexRegisteredService"> <property name="id" value="0" /> <property name="name" value="HTTP and IMAP" /> <property name="description" value="Allows HTTP(S) and IMAP(S) protocols" /> <property name="serviceId" value="^(https?|imaps?)://.*" /> <property name="evaluationOrder" value="10000001" /> <property name="ignoreAttributes" value="true"/> </bean>
最后修改WEB-INF\view\jsp\protocol\2.0\casServiceValidationSuccess.jsp文件
<%@page pageEncoding="UTF-8"%> <%@ page session="false" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %> <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'> <cas:authenticationSuccess> <cas:user>${fn:escapeXml(assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.id)}</cas:user> <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> <!-- 在server验证成功后,这个页面负责生成与客户端交互的xml信息,在默认的casServiceValidationSuccess.jsp中,只包括用户名,并不提供其他的属性信息,因此需要对页面进行扩展 --> <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> </cas:authenticationSuccess> </cas:serviceResponse>
然后即可使用以下代码在index.jsp中获取对应的返回对象:
AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal(); Map<String, Object> attributes = principal.getAttributes();
以下是我用于测试的index.jsp
<%@ page language="java" import="java.util.*" contentType="text/html;charset=utf-8"%> <%@ page import="org.jasig.cas.client.authentication.AttributePrincipal,org.jasig.cas.client.validation.Assertion,org.jasig.cas.client.util.AbstractCasFilter"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>CAS单点登录VS退出</title> </head> <body> <% AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal(); Map<String, Object> attributes = principal.getAttributes(); /*for(Map.Entry<String,Object> m: attributes.entrySet()){ System.out.println(m.getKey()+"---"+m.getValue()); }*/ %> [ 单点登录测试 ]<br /><br /> 用户名:<%=principal.getName()%><br /> id:<%=attributes.get("id")%><br /> email:<%=attributes.get("email")%><br /> emailValidated:<%=attributes.get("emailValidated")%><br /> password:<%=attributes.get("password")%><br /> registerTime:<%=attributes.get("registerTime")%><br /> lastLoginTime:<%=attributes.get("lastLoginTime")%><br /> balance:<%=attributes.get("balance")%><br /> <br /> <a href="http://localhost:8080/sway/cas/logout">退出</a><br /><br /> <hr/> <br /><br /> [ DEBUG ]<br /><br /> map中元素个数为<%=attributes.size()%> </body> </html>
至此配置完毕,往后再教大家配置对应的SSL加密。