单点登录系统CAS搭建及取得更多用户信息的实现
服务端下载地址 http://developer.jasig.org/cas/ https://github.com/Jasig/cas/releases
客户端下载地址 http://developer.jasig.org/cas-clients/ http://downloads.jasig.org/cas-clients/
一、 单点登录简介
单点登录(Single sign-on,简称为 SSO),是目前比较流行的企业业务整合的解决方案之一。其简单定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。类似的,用户只需要执行一次退出操作就可以终止对所有相关应用系统的访问。
本文主旨在介绍如何使用CAS实现单点登录时取得更多的用户信息,单点登录的原理将不作阐述。
二、 CAS简介
CAS是CentralAuthentication Service即中央认证服务的简称,它是由耶鲁大学发起的开源项目,其目的是为Web系统提供可靠的单点登录机制。2004年12月CAS正式成为JASIG(jasig.org)的一个项目。
CAS的Server需要作为独立Web应用部署,并且当前Server仅支持Java,但其Client端则支持Java、.Net、PHP、Perl、Apache、uPortal、Ruby等多种开发语言。
各版本的CAS可以分别从以下地址下载。
CAS Server的下载地址:http://downloads.jasig.org/cas/
CAS Client的下载地址:http://downloads.jasig.org/cas-clients/
本文验证环境使用CASServer 3.5.2、CAS Client 3.2.1(Java Client端)、CAS1.3.2(PHP Client端)。当前网上可查找到的大部分资料并不适用于CAS Server 3.5.2,因此如果使用其它版本本文可能也存在不适用的情况。
三、 CAS部署、基本配置与使用
1. Server端部署
将下载的CASServer压缩包解压,可以发现这个包中已经包含了Server侧的全部源代码及编译完成的Jar及war包。将modules目录下的cas-server-webapp-3.5.2.war拷贝至Tomcat的webapps下后启动Tomcat即可完成部署。
上述war包中包含了Server的版本号,因此部署完成后的应用访问URL中也会包含版本信息。如果期望为Client端提供更多的伸缩性和兼容性,可以在启动Tomcat前将war包的名称修改为cas.war。这样如果以后Server端进行升级,Client端也不需要做任何修改。
部署完成并启动Tomcat以后,就可以在浏览器中输入对应的URL(例如:http://192.168.202.176:8080/cas)访问CAS了。CAS Server提供的默认界面如下图所示。
在Username与Password输入框中输入相同的字符即可成功登录,登录成功后的界面如下图。
2. Server端配置
上述部署完成的Server存在两个问题,一是通过HTTP协议访问服务安全性较差,通常应当使用HTTPS协议以提供较高的安全性;另一方面登录账号与密码其实与系统不存在关联,不能在实际应用中加以使用,因此需要进一步做一些配置解决上述问题。
2.1 配置Tomcat的HTTPS协议
为Tomcat配置HTTPS协议分为两步,一是为Tomcat生成服务证书并将对应CA根证书导入keystore的可信列表中,二是修改Tomcat的配置文件。
关于证书生成,不同的应用场景与需求其具体过程会有一些差异。如果对此没有特殊要求,可以采用最为简单的自签名证书。其具体生成过程简述如下:
创建一个用于保存证书的目录,然后通过cmd命令进入命令提示符窗口,并将当前工作目录切换至刚刚创建的用于保存证书的目录(Linux系统过程类似)。随后执行以下命令,其中红色部分可以根据实际需要加以替换:
keytool-genkey -aliascas_key -keyalg RSA -storepass yanzhijun -keystorecas.keystore-validity 3600
注意:如果上述命令执行时提示找不到keytool,请检查环境变量JAVA_HOME和PATH是否已正确配置。
随后,keytool会提示输入一些与证书相关的信息,例如可以依次输入下图中所示值。其中特别要注意的是要输入的第一项“passport.yanzhijun.net”必须要输入CAS Server的实际域名或IP,否则在后面建立HTTPS连接时将不能建立可信连接。其它项可以根据实际情况输入或随意输入合法值即可。
上述命令成功执行以后,将生成名为cas.keystore的文件,Tomcat将使用它来建立HTTPS连接。
通常CAS Client端与Server端进行通信时也使用HTTPS协议并通过证书对Server进行身份确认,因此还需要将上述步骤中生成的证书导出备用。以下命令将证书导出为名为cas.cer的文件:
keytool-export -trustcacerts -alias cas_key -file cas.cer -keystore cas.keystore-storepass yanzhijun
注意:上述命令中的参数要与生成证书的命令中的参数保持对应一致。
完成证书生成以后,还需要对Tomcat的配置文件conf/server.xml进行修改。首先将标签Connectorport="8443"前后的注释删除,然后将其修改为类似以下内容:
<Connectorport="8443"protocol="org.apache.coyote.http11.Http11NioProtocol"SSLEnabled="true"
maxThreads="150" scheme="https"secure="true"
clientAuth="false" sslProtocol="TLS"
keystoreFile="C:/cert/cas.keystore"
keystorePass="yanzhijun"/>
注意:keystoreFile与keystorePass要与生成证书时输入的参数保持一致。
至此,Tomcat的HTTPS协议配置完成,重新启动Tomcat,就可以使用HTTPS协议访问cas了(例如https://passport.yanzhijun.net:8443/cas)。如果必要,可以将前述生成的cas.cer导入系统或浏览器的证书库中,以便访问CAS Server时浏览器不再显示警告信息。
2.2 配置CAS从数据库中取得数据验证登录的有效性
CASServer提供了多种身份验证方法,可以配置文件WEB-INF/deployerConfigContext.xml中对其加以修改。
在deployerConfigContext.xml中查找“<property name="authenticationHandlers">”,其中以下配置表明登录时Username与Password一致则通过验证。
<bean class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePasswordAuthenticationHandler"/>
要使用数据库中的信息对登录进行验证,需要将上述bean配置项注释或删除掉,然后在对应位置添加以下配置:
<beanclass="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">
<property name="sql" value="selectpassword fromuserinfowhereuserName=?" />
<property name="dataSource" ref="dataSource"/>
</bean>
其中userinfo是保存用户信息的表名,userName是表userinfo中存储用户名的字段名称,password则是表userinfo中存储用户密码(或加密后的密码)的字段名称。
如果数据库中的密码是加密存储的(通常都应加密存储),则上述配置中需要增加名为“passwordEncoder”的property指定加密方法。例如以下配置指定了以SHA加密密码。
<propertyname="passwordEncoder">
<beanclass="org.jasig.cas.authentication.handler.DefaultPasswordEncoder">
<constructor-argvalue="SHA"/>
</bean>
</property>
在指定从数据库中查询用户信息进行验证时,同时指定了要使用数据源dataSource,因此还需要对数据源进行配置。以下数据源配置使用位于本机的MySQL数据库,可以将其配置在节点beans下的任意位置。
<beanid="dataSource"class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"value="com.mysql.jdbc.Driver"></property>
<property name="url"value="jdbc:mysql://localhost:3306/cas_usr"></property>
<property name="username"value="cas_usr"></property>
<property name="password"value="123"></property>
</bean>
注意:使用数据库时需要将与之对应的数据库Java驱动拷入WEB-INF/lib目录下。
至此,CAS Server全部搭建完成。
3. Java Client端配置与使用
首先需要将下载的JavaClient压缩包解压并在解压后将modules目录下的cas-client-core-3.2.1.jar及commons-logging-1.1.jar拷入准备集成CAS的Web应用的WEB-INF/lib下。
随后需要在Web应用的web.xml文件中添加CAS的相关配置,具体配置项如下,请注意修改其中CAS Server的地址、端口信息及当前应用的地址、端口信息。
<filter>
<filter-name>CASAuthentication Filter</filter-name>
<filter-class>
org.jasig.cas.client.authentication.AuthenticationFilter
</filter-class>
<!-- CAS验证服务器地址-->
<init-param>
<param-name>casServerLoginUrl</param-name>
<param-value>
https://passport.yanzhijun.net:8443/cas/login
</param-value>
</init-param>
<init-param>
<param-name>renew</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>gateway</param-name>
<param-value>false</param-value>
</init-param>
<!--客户端应用服务器地址-->
<init-param>
<param-name>serverName</param-name>
<param-value>http://192.168.202.176:8080</param-value>
</init-param>
</filter>
<!--负责Ticket校验-->
<filter>
<filter-name>CASValidation Filter</filter-name>
<filter-class>
org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter
</filter-class>
<!-- CAS验证服务器地址(上下文) -->
<init-param>
<param-name>casServerUrlPrefix</param-name>
<param-value>https://passport.yanzhijun.net:8443/cas/</param-value>
</init-param>
<!--客户端应用服务器地址-->
<init-param>
<param-name>serverName</param-name>
<param-value>http://192.168.202.176:8080</param-value>
</init-param>
<init-param>
<param-name>useSession</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>redirectAfterValidation</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter>
<filter-name>CASHttpServletRequest Wrapper Filter</filter-name>
<filter-class>
org.jasig.cas.client.util.HttpServletRequestWrapperFilter
</filter-class>
</filter>
<filter>
<filter-name>CASAssertion Thread Local Filter</filter-name>
<filter-class>
org.jasig.cas.client.util.AssertionThreadLocalFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>CAS AuthenticationFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CASValidation Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS HttpServletRequestWrapper Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CASAssertion Thread Local Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
至此,CAS机制已经可以发挥作用了,如果尝试打开Web应用,可以发现页面跳转到了CAS Server的登录页面,输入正确的Username与Password并提交后页面又跳转回当前Web应用。不过通常Web应用程序也需要知道当前登录的用户名称,以下示例JSP页面显示了在Web应用中获取当前登录用户名的几种方法。
<%@pageimport="org.jasig.cas.client.authentication.AttributePrincipal" %>
<%@page import="org.jasig.cas.client.validation.Assertion"%>
<%
String loginName1 = request.getRemoteUser();
%>
request.getRemoteUser(): <%=loginName1%><br/>
<%
AttributePrincipal principal = (AttributePrincipal)request.getUserPrincipal();
String loginName2 = principal.getName();
%>
request.getUserPrincipal().getName():<%=loginName2%><br/>
<%
Object object =request.getSession().getAttribute("_const_cas_assertion_");
Assertion assertion =(Assertion)object;
String loginName3 =assertion.getPrincipal().getName();
%>
request.getSession().getAttribute("_const_cas_assertion_").getPrincipal().getName():<%=loginName3%><br/>
查看上述代码运行后输出的结果,可以看到三种方式取得的用户称是一样的,均与登录时的名称保持一致。
4. PHP Client端使用
解压PHP Client压缩包,将文件夹CAS及文件CAS.php拷至需要集成CAS的PHP应用的适当位置。修改docs/examples目录下的文件example_simple.php如下,并令example_simple.php与文件夹CAS及文件CAS.php同一目录,在浏览器中访问example_simple.php,页面将显示当前登录的用户名称。
<?php
require_once'CAS.php';
phpCAS::client(CAS_VERSION_2_0,'passport.yanzhijun.net',8443, '/cas');
phpCAS::setNoCasServerValidation();
phpCAS::forceAuthentication();
if(isset($_REQUEST['logout'])) {
phpCAS::logout();
}
// forthis test, simply print that the authentication was successfull
?>
<html>
<head>
<title>phpCAS simpleclient</title>
</head>
<body>
<h1>Successfull Authentication!</h1>
<p>the user's login is<b><?php echo phpCAS::getUser(); ?></b>.</p>
<p>phpCAS version is<b><?php echo phpCAS::getVersion(); ?></b>.</p>
<p><ahref="?logout=">Logout</a></p>
</body>
</html>
四、 CAS单点登录取得更多用户信息
通过上述部署与配置,多个Web应用已经可以共用一个登录服务。但是,上述过程中作为CAS Client端的Web应用只取得了用户登录名称信息,而在实际应用中,Web应用往往需要获得登录用户更多的信息,例如会员等级、性别、住址等。要达到此目的,只需对Server端稍做修改即可实现。
1. 服务端配置及修改
假定上述存储用户信息的数据表userinfo中还包含一个名为address的用于存储用户地址的字段,而Web应用程序希望能够从CAS Server处获得当前登录用户的地址信息,则Server端需要按以下内容修改deployerConfigContext.xml。部分配置说明请参见注释。
<!--将原有attributeRepository配置注释 -->
<!--
<beanid="attributeRepository"
class="org.jasig.services.persondir.support.StubPersonAttributeDao">
<propertyname="backingMap">
<map>
<entrykey="uid" value="uid" />
<entrykey="eduPersonAffiliation" value="eduPersonAffiliation"/>
<entrykey="groupMembership" value="groupMembership" />
</map>
</property>
</bean>
-->
<!--新增attributeRepository配置(开始) -->
<bean class="org.jasig.services.persondir.support.jdbc.SingleRowJdbcPersonAttributeDao"id="attributeRepository">
<!-- 指定使用的数据源,此处dataSource是已配置好的数据源 -->
<constructor-arg index="0"ref="dataSource"/>
<!-- 从数据库中查询信息的SQL语句,通常只需要修改表名即可 -->
<constructor-arg index="1" value="select * from userinfo where {0}"/>
<propertyname="queryAttributeMapping">
<map>
<!-- 上述查询的参数这里的key为username不变,将userName替换为表中表示用户名的字段名称 -->
<entrykey="username" value="userName"/>
</map>
</property>
<propertyname="resultAttributeMapping">
<map>
<!-- 需要返回给Web应用的其它信息,多个信息时可继续增加entry节点-->
<!--key值为数据表中的字段名称,value值为Client端取值时的名称标识-->
<entry key="address" value="address"/>
</map>
</property>
</bean>
<!--新增attributeRepository配置(结束) -->
<bean
id="serviceRegistryDao"
class="org.jasig.cas.services.InMemoryServiceRegistryDaoImpl">
<propertyname="registeredServices">
<list>
<beanclass="org.jasig.cas.services.RegexRegisteredService">
<propertyname="id" value="0" />
<propertyname="name" value="HTTP and IMAP" />
<propertyname="description" value="Allows HTTP(S) and IMAP(S)protocols" />
<propertyname="serviceId" value="^(https?|imaps?)://.*" />
<propertyname="evaluationOrder" value="10000001" />
<!--增加此项配置 -->
<!-- <property name="ignoreAttributes" value="true"/> -->
<property name="alloweAttributes" >
<list>
<value>phones</value>
<value>uid</value>
<value>createDate</value>
</list>
</property>
</bean>
</list>
</property>
</bean>
CASServer要将额外的信息传递至Client端,还需要修改完成信息组装的文件WEB-INF/view/jsp/protocol/2.0/casServiceValidationSuccess.jsp。casServiceValidationSuccess.jsp负责组装包含用户信息的XML,因此修改部分是将需要传递的额外信息加入到它最终生成的XML文件之中。具体修改如下:
<cas:serviceResponsexmlns: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:iftest="${fn:length(assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.attributes)> 0}">
<cas:attributes>
<c:forEachvar="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)}>
//或者(修改乱码)记得导入<%@ page session="false" contentType="application/xml; charset=UTF-8" import="java.net.URLEncoder" %>
<c:set var="val" value="${attr.value}"/>
<cas:${attr.key}><%=URLEncoder.encode((String)pageContext.getAttribute("val"),"UTF-8")%></cas:${attr.key}>
</c:forEach>
</cas:attributes>
</c:if>
<!-- 新增额外信息(结束) -->
<c:if test="${not emptypgtIou}">
<cas:proxyGrantingTicket>${pgtIou}</cas:proxyGrantingTicket>
</c:if>
<c:if test="${fn:length(assertion.chainedAuthentications)> 1}">
<cas:proxies>
<c:forEachvar="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>
2. Java Client端取得更多用户信息
Java Client端不需要做任何修改就可以继续正常使用CAS服务,如果需要取得用户更多信息,可以通过AttributePrincipal对象取得Attribute列表(一个Map对象)后进行查询。
修改前述Java Client的示例代码,在最后追加取得address信息的代码,重启服务并重新访问页面,可以看到页面上显示了当前用户的address信息。
<%@pageimport="org.jasig.cas.client.authentication.AttributePrincipal" %>
<%@pageimport="org.jasig.cas.client.validation.Assertion" %>
<%@page import="java.util.*" %>
<%
String loginName1 = request.getRemoteUser();
%>
request.getRemoteUser(): <%=loginName1%><br/>
<%
AttributePrincipal principal = (AttributePrincipal)request.getUserPrincipal();
String loginName2 = principal.getName();
%>
request.getUserPrincipal().getName():<%=loginName2%><br/>
<%
Object object =request.getSession().getAttribute("_const_cas_assertion_");
Assertion assertion =(Assertion)object;
String loginName3 =assertion.getPrincipal().getName();
%>
request.getSession().getAttribute("_const_cas_assertion_").getPrincipal().getName():<%=loginName3%><br/>
<br/>
<%
// 以下代码取得address信息
Map<String, Object> attributes = principal.getAttributes();
Iterator it = attributes.keySet().iterator();
String address = "NoAddress";
Object oaddress=attributes.get("address");
if(oaddress != null)
{
address =oaddress.toString();
}
%>
address:<%=address%><br/>
相关推荐
CAS(Central Authentication Service)是一种广泛使用的开放源码身份验证框架,它允许用户通过单一登录(Single Sign-On,SSO)访问多个应用系统。这个压缩包包含的是CAS服务器的4.2.1版本的源代码,以及使用Gradle...
CAS(Central Authentication Service)是一款广泛使用的开源身份验证框架,它实现了单点登录(Single Sign-On, SSO)功能,允许用户在多个应用系统中只需一次登录即可访问所有系统,极大地提高了用户体验和安全性。...
2. **SAML 1.1**:CAS 支持的另一种安全声明标记语言,用于在不同安全域之间传递用户身份信息。SAML 提供了更复杂的身份验证和授权功能,例如属性查询和审计。 3. **OAuth**:CAS 也支持 OAuth 协议,允许第三方...
尽管3.5.2版本提供了更多的特性和改进,但3.4.11仍是一个可靠的选择,尤其对于那些已经熟悉这个版本并能满足其需求的环境。然而,为了获得最新的安全更新和功能,建议适时考虑升级到更现代的版本。
需要注意的是,这只是一个基础示例,实际部署时需要考虑更多的安全因素,如错误处理、票证的加密和解密、会话过期策略、以及更复杂的身份验证和授权逻辑。此外,真实项目中通常会使用更安全的方法来存储和处理用户...
2. 集成性增强:此版本支持与更多应用系统集成,如LDAP、Active Directory等,提供了丰富的API和过滤器,便于开发者将CAS集成到现有的IT环境中。 3. 性能优化:针对大规模用户环境,3.3.3版本进行了性能调优,提高了...
CAS(中央认证服务)是一个基于Web的协议,它允许用户只需一次登录就能访问多个应用系统。它的主要目标是提高安全性,减少用户记住多套用户名和密码的负担,同时简化系统的身份验证流程。 在"cas-server-3.5.2-...
- **扩展CAS服务**:开发新的服务模块,例如支持更多类型的认证源或集成新的应用系统。 - **调试和修复问题**:遇到问题时,可以通过源码跟踪定位,调试和修复错误。 总之,"cas-server-3.5.0-release"是一个完整的...
CAS 5.x是CAS的一个较新版本,提供了更多的特性和安全增强。搭建基础涉及安装Java开发环境(如JDK 8或更高版本),选择合适的服务器(如Apache Tomcat),以及下载并部署CAS服务器应用到服务器上。 2. **Java...
**CAS (Central Authentication Service)** 是一个开源的身份验证框架,主要功能是提供统一的用户身份验证服务,允许用户在多个应用系统中只需要登录一次即可访问所有相互信任的应用。CAS的核心概念包括服务提供商和...
SSO(Single Sign-On)是单点登录的缩写,是一种网络用户身份验证的机制,允许用户在一次登录后访问多个应用系统,而无需再次进行身份验证。在企业级环境中,这种技术极大地提高了用户体验,同时减少了管理多个独立...
CAS(Central Authentication Service)是一种基于Web的单一登录(Single Sign-On, SSO)协议,它允许用户通过一个统一的身份验证系统访问多个应用系统,而无需多次登录。在本项目" CAS-server -3.4 myeclipse工程...
1. **用户界面**:Assets 文件提供了用户首次接触 CAS 时看到的登录界面,包括输入用户名和密码的表单,以及错误提示信息等。 2. **交互逻辑**:JavaScript 代码处理用户与界面的交互,如表单验证、重定向逻辑等,...
CAS(Central Authentication Service)是一种广泛使用的开放源代码的单点登录(Single Sign-On,简称SSO)协议,它为各种应用程序提供了一种集中式的身份验证服务。本项目是CAS服务器的web应用程序版本3.5.2,以rar...
搭建CAS Server的第一步是准备开发环境,确保你有JDK 8或以上以及Maven 3.0+已经安装。在Windows环境下,`mvnw.bat`文件是Maven的可执行脚本,而在Unix/Linux系统中,对应的文件是`mvnw`。这两个文件都是用来运行...
为了支持更多用户和更复杂的身份验证场景,可以配置CAS使用数据库进行用户验证。这涉及到数据库连接配置、数据表结构设计等。 #### 三、CAS与Liferay集成 **2.5 CAS与Liferay集成** **2.5.1 客户端证书认证** ...
- `client1.zhoubang85.com`:对应部署第一个客户端应用的Tomcat实例。 - `client2.zhoubang85.com`:对应部署第二个客户端应用的Tomcat实例。 2. **安全证书配置**:由于CAS系统默认基于HTTPS协议运行,因此需要...
OAuth2 更适用于第三方应用获取用户资源的场景,而CAS 则更适合企业内部多应用系统间的统一认证需求。两者在提升用户体验的同时,确保了安全性,是现代Web应用体系中不可或缺的身份管理和授权工具。
SSO(Single Sign-On)单点登录是一种身份验证机制,允许用户在多个应用程序中使用一组共享的认证凭据,如...通过这些知识点,开发者可以更好地理解和构建自己的SSO解决方案,提供给用户更便捷、安全的多应用登录体验。