Apache CAS部署在tomcat上实现单点登录
2016-04-08 23:33
549 查看
单点登录(Single Sign On , 简称 SSO )是目前比较流行的服务于企业业务整合的解决方案之一, SSO 使得在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。CAS(Central Authentication Service)是一款不错的针对 Web 应用的单点登录框架,本文介绍了 CAS 的原理、协议、在 Tomcat 中的配置和使用,对于采用 CAS 实现轻量级单点登录解决方案的入门读者具有一定指导作用。
1.CAS介绍
CAS 是 Yale 大学发起的一个开源项目,旨在为 Web 应用系统提供一种可靠的单点登录方法,CAS 在 2004 年 12 月正式成为 JA-SIG 的一个项目。
CAS 具有以下特点:
(1)开源的企业级单点登录解决方案。
(2)CAS Server 为需要独立部署的 Web 应用。
(3)CAS Client 支持非常多的客户端(这里指单点登录系统中的各个 Web 应用),包括 Java, .Net, PHP, Perl, Apache, uPortal, Ruby 等。
2.CAS原理和协议
从结构上看,CAS 包含两个部分: CAS Server 和 CAS Client。CAS Server 需要独立部署,主要负责对用户的认证工作;CAS Client 负责处理对客户端受保护资源的访问请求,需要登录时,重定向到 CAS Server。图1 是 CAS 最基本的协议过程:
图1 CAS基础协议
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 官方网站上的相关文档。
3.准备工作
下载CAS Server:https://www.apereo.org/projects/cas/download-cas
下载CAS Client :http://developer.jasig.org/cas-clients/
下载Tomcat : 本文用的是Tomcat 8.0,自己去官网下载即可。
4. 生成https的证书文件
为了在Tomcat启用SSL,使其支持https访问,需要生产证书文件。
这里需要使用JDK安装包下的keytool工具生成证书文件keystore,以命令方式换到目录%TOMCAT_HOME%,在command命令行输入如下命令:
keytool -genkey -alias tomcat_key -keyalg RSA -storepass changeit -keystore server.keystore -validity 36500
此时会提示用户输入姓名,组织等信息,如下所示,只输入localhost作为name,其余回车即可
这样就会在当前路径下生成一个名为server.keystore的证书文件,这个文件会在后面tomcat的server.xml配置文件中用到。
简单解释下这个命令的含义:
-genkey 生成证书指令
-alias 证书的别名为tomcat_key
-keyalg 生成证书的算法是RSA
-storepass 证书的密码changeit
-keystore 生成的证书文件是server.keystore 这里也可以指定具体的路径,如在Mac下:~/Document表示用户目录下的Document文件夹下
-validity 36500 证书的有效期,单位是天,这里指定的是100年
5.配置 Tomcat 使用 Https 协议
在Tomcat的server.xml配置文件中进行如下配置:
这里的keystoreFile需要指定上一步生成的证书文件,keystorePass对应生成文件的时候设置的密码。
6.部署CAS Server到Tomcat
(1)到cas官网下载cas-server http://developer.jasig.org/cas/(我下载的是4.0.0)
(2)解压压缩文件,在解压后的文件夹内找到/modules/cas-server-webapp-4.0.0.war。将其复制到%Tomcat_Home%\webapps下并改名为cas.war
(3)启动Tomcat,并测试 https://localhost:8443/cas 看是否访问正常(默认输入用户名和密码一致就可以)。
CAS Server 4.0.0 默认登陆验证方式是 AcceptUsersAuthenticationHandler (老版本好像是SimpleTestUsernamePasswordAuthenticationHandler),默认用户名/密码为 casuser/Mellon(cas/WEB-INF/deployerConfigContext.xml 中找到 id=primaryAuthenticationHandler
的bean查看,里面的map也可以自己增加更多个)。我们通常需要从数据库中取出用户名和密码进行验证,所以我们需要修改 deployerConfigContext.xml,配置我们自己的服务认证方式。
虽然 CAS Server 已经部署成功,但这只是一个缺省的实现,在实际使用的时候,还需要根据实际概况做扩展和定制,最主要的是扩展认证 (Authentication) 接口和 CAS Server 的界面。
7. 扩展认证接口
CAS Server 负责完成对用户的认证工作,它会处理登录时的用户凭证 (Credentials) 信息,用户名/密码对是最常见的凭证信息。CAS Server 可能需要到数据库检索一条用户帐号信息,也可能在 XML 文件中检索用户名/密码,还可能通过 LDAP Server 获取等,在这种情况下,CAS 提供了一种灵活但统一的接口和实现分离的方式,实际使用中 CAS 采用哪种方式认证是与CAS的基本协议分离开的,用户可以根据认证的接口去定制和扩展。
扩展 AuthenticationHandler
CAS 提供扩展认证的核心是 AuthenticationHandler 接口,该接口定义如清单 1 下:
清单 1. AuthenticationHandler定义
该接口定义了 2 个需要实现的方法,supports ()方法用于检查所给的包含认证信息的Credentials 是否受当前 AuthenticationHandler 支持;而 authenticate() 方法则担当验证认证信息的任务,这也是需要扩展的主要方法,根据情况与存储合法认证信息的介质进行交互,返回 boolean 类型的值,true 表示验证通过,false 表示验证失败。
CAS3中还提供了对AuthenticationHandler 接口的一些抽象实现,比如,可能需要在执行authenticate() 方法前后执行某些其他操作,那么可以让自己的认证类扩展自清单 2 中的抽象类:
清单 2. AbstractPreAndPostProcessingAuthenticationHandler定义
成为了子类必须要实现的方法。
由于实际运用中,最常用的是用户名和密码方式的认证,CAS3 提供了针对该方式的实现,如清单 3 所示:
清单 3. AbstractUsernamePasswordAuthenticationHandler 定义
基于用户名密码的认证方式可直接扩展自 AbstractUsernamePasswordAuthenticationHandler,验证用户名密码的具体操作通过实现 authenticateUsernamePasswordInternal() 方法达到,另外,通常情况下密码会是加密过的,setPasswordEncoder() 方法就是用于指定适当的加密器。
从以上清单中可以看到,doAuthentication() 方法的参数是 Credentials 类型,这是包含用户认证信息的一个接口,对于用户名密码类型的认证信息,可以直接使用 UsernamePasswordCredentials,如果需要扩展其他类型的认证信息,需要实现Credentials接口,并且实现相应的 CredentialsToPrincipalResolver 接口,其具体方法可以借鉴 UsernamePasswordCredentials 和 UsernamePasswordCredentialsToPrincipalResolver。
8.实现JDBC的认证
用户的认证信息通常保存在数据库中,因此本文就选用这种情况来介绍。将前面下载的 cas-server-{version}-release.zip 包解开后,在 modules 目录下可以找到包 cas-server-support-jdbc-{version}.jar,其提供了通过 JDBC 连接数据库进行验证的缺省实现,基于该包的支持,我们只需要做一些配置工作即可实现 JDBC 认证。
JDBC 认证方法支持多种数据库,DB2, Oracle, MySql, Microsoft SQL Server 等均可,这里以Mysql作为例子介绍。并且假设Mysql数据库名:test,数据库登录用户名: root,数据库登录密码:password,用户信息表为: t_user,该表包含用户名和密码的两个数据项分别为 username 和 password。用户表数据如下图所示:
1)配置DataSource
打开文件 cas/WEB-INF/deployerConfigContext.xml,添加一个新的 bean 标签,以MYSQL为例,内容如清单 4 所示:
2)配置 AuthenticationHandler
CAS 4.0.0 提供了 3 个基于 JDBC 的 AuthenticationHandler,分别为 BindModeSearchDatabaseAuthenticationHandler, QueryDatabaseAuthenticationHandler, SearchModeSearchDatabaseAuthenticationHandler。
- BindModeSearchDatabaseAuthenticationHandler 是用所给的用户名和密码去建立数据库连接,根据连接建立是否成功来判断验证成功与否;
- QueryDatabaseAuthenticationHandler 通过配置一个 SQL 语句查出密码,与所给密码匹配;
- SearchModeSearchDatabaseAuthenticationHandler 通过配置存放用户验证信息的表、用户名字段和密码字段,构造查询语句来验证。
使用哪个 AuthenticationHandler,需要在 deployerConfigContext.xml 中设置,默认情况下,CAS 4.0.0 使用 AcceptUsersAuthenticationHandler(上面已经提到,需要在 deployerConfigContext.xml 中查看)。
在 deployerConfigContext.xml 文件中可以找到如下配置:
这里我们注释掉这段配置,然后换成我们希望的一个 AuthenticationHandler,比如,使用QueryDatabaseAuthenticationHandler 或 SearchModeSearchDatabaseAuthenticationHandler 可以分别选取清单 5 或清单 6 的配置。
清单 5. 使用 QueryDatabaseAuthenticationHandler
清单 7. QueryDatabaseAuthenticationHandler配置加密器类
注意:DataSource 依赖于 commons-collections-3.2.jar、commons-dbcp-1.2.1.jar、commons-pool-1.3.jar、数据库驱动包、cas对jdbc的支持包cas-server-support-jdbc-4.0.0.jar,需要找到这几个jar包放进 %TOMCAT_HOME%/webapps/cas/WEB-INF/lib 目录。
然后便可以启动Tomcat使用数据库中的用户名和密码进行登录测试了。
注意:DataSource 依赖于 commons-collections-3.2.jar、commons-dbcp-1.2.1.jar、commons-pool-1.3.jar、数据库驱动包、cas对jdbc的支持包cas-server-support-jdbc-4.0.0.jar,需要找到这几个jar包放进 %TOMCAT_HOME%/webapps/cas/WEB-INF/lib 目录。
然后便可以启动Tomcat使用数据库中的用户名和密码进行登录测试了。
9.部署CAS客户端应用
单点登录的目的是为了让多个相关联的应用使用相同的登录过程,本文在讲解过程中构造 2个简单的应用,分别以 CASClient1 和 CASClient2 来作为示例,它们均只有一个页面,显示欢迎信息和当前登录用户名。这两个应用使用同一套登录信息,并且只有登录过的用户才能访问,通过本文的配置,实现单点登录,即只需登录一次就可以访问这两个应用。应用的工程结构很简单,引入必要的jar包,然后新建一个index.jsp页面。
index.jsp代码清单
10.配置CAS客户端Filter
在CAS的client端的web.xml文件中配置过滤器如下:
<!-- 该过滤器用于实现单点登出功能,可选配置。 -->
<!-- 登出地址 https://casserver:8443/cas/logout -->
<filter>
<filter-name>CAS Single Sign Out Filter</filter-name>
<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
</filter>
<!-- 该过滤器负责用户的认证工作,必须启用它 -->
<filter>
<filter-name>CAS Authentication Filter</filter-name>
<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
<init-param>
<param-name>casServerLoginUrl</param-name>
<param-value>https://localhost:8443/cas/login</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>http://localhost:8080</param-value>
</init-param>
</filter>
<!-- 该过滤器负责对Ticket的校验工作,必须启用它 -->
<filter>
<filter-name>CAS Validation Filter</filter-name>
<filter-class>org.jasig.cas.client.validation.Cas10TicketValidationFilter</filter-class>
<init-param>
<param-name>casServerUrlPrefix</param-name>
<param-value>https://localhost:8443/cas</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>http://localhost:8080</param-value>
</init-param>
<init-param>
<param-name>redirectAfterValidation</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<!-- 该过滤器负责实现HttpServletRequest请求的包装, 比如允许开发者通过HttpServletRequest的getRemoteUser()方法获得SSO登录用户的登录名,可选配置。 -->
<filter>
<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
<filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
</filter>
<!-- 该过滤器使得开发者可以通过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 Single Sign Out Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS Authentication Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS Validation Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS Assertion Thread Local Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>
运行Client工程,首次访问任一页面就会跳转到https://localhost:8443/cas/login进行认证。
把你的退出链接设置为:https://localhost:8443/cas/logout 即可实现单点登出,如果需要在系统退出后返回指定页面,我们可以修改源码在logout后面增加参数来实现。
11.单点登录测试同时运行CAS server、 CASClient1 和CASClient2。分别访问下面的URL:
CASClient1:
localhost:8080/CASClient1/index.jsp
CASClient2: localhost:8080/CASClient2/index.jsp
当第一次访问上面的URL时,会重定向到下面的页面:
这时输入数据库中的用户名和对应的密码登录,登录成功后会看到如下页面:
此时访问第二个URL发现index页面会直接打开,而不用再次登录,因为访问CASClient1的时候已经认证过了。这就实现了所谓的单点登录。
1.CAS介绍
CAS 是 Yale 大学发起的一个开源项目,旨在为 Web 应用系统提供一种可靠的单点登录方法,CAS 在 2004 年 12 月正式成为 JA-SIG 的一个项目。
CAS 具有以下特点:
(1)开源的企业级单点登录解决方案。
(2)CAS Server 为需要独立部署的 Web 应用。
(3)CAS Client 支持非常多的客户端(这里指单点登录系统中的各个 Web 应用),包括 Java, .Net, PHP, Perl, Apache, uPortal, Ruby 等。
2.CAS原理和协议
从结构上看,CAS 包含两个部分: CAS Server 和 CAS Client。CAS Server 需要独立部署,主要负责对用户的认证工作;CAS Client 负责处理对客户端受保护资源的访问请求,需要登录时,重定向到 CAS Server。图1 是 CAS 最基本的协议过程:
图1 CAS基础协议
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 官方网站上的相关文档。
3.准备工作
下载CAS Server:https://www.apereo.org/projects/cas/download-cas
下载CAS Client :http://developer.jasig.org/cas-clients/
下载Tomcat : 本文用的是Tomcat 8.0,自己去官网下载即可。
4. 生成https的证书文件
为了在Tomcat启用SSL,使其支持https访问,需要生产证书文件。
这里需要使用JDK安装包下的keytool工具生成证书文件keystore,以命令方式换到目录%TOMCAT_HOME%,在command命令行输入如下命令:
keytool -genkey -alias tomcat_key -keyalg RSA -storepass changeit -keystore server.keystore -validity 36500
此时会提示用户输入姓名,组织等信息,如下所示,只输入localhost作为name,其余回车即可
这样就会在当前路径下生成一个名为server.keystore的证书文件,这个文件会在后面tomcat的server.xml配置文件中用到。
简单解释下这个命令的含义:
-genkey 生成证书指令
-alias 证书的别名为tomcat_key
-keyalg 生成证书的算法是RSA
-storepass 证书的密码changeit
-keystore 生成的证书文件是server.keystore 这里也可以指定具体的路径,如在Mac下:~/Document表示用户目录下的Document文件夹下
-validity 36500 证书的有效期,单位是天,这里指定的是100年
5.配置 Tomcat 使用 Https 协议
在Tomcat的server.xml配置文件中进行如下配置:
<Connector SSLEnabled="true" clientAuth="false" maxThreads="150" port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" scheme="https" secure="true" sslProtocol="TLS" keystoreFile="/Users/cruise/Documents/ISG/apache-tomcat-8.0.32/server.keystore" keystorePass="changeit" />
这里的keystoreFile需要指定上一步生成的证书文件,keystorePass对应生成文件的时候设置的密码。
6.部署CAS Server到Tomcat
(1)到cas官网下载cas-server http://developer.jasig.org/cas/(我下载的是4.0.0)
(2)解压压缩文件,在解压后的文件夹内找到/modules/cas-server-webapp-4.0.0.war。将其复制到%Tomcat_Home%\webapps下并改名为cas.war
(3)启动Tomcat,并测试 https://localhost:8443/cas 看是否访问正常(默认输入用户名和密码一致就可以)。
CAS Server 4.0.0 默认登陆验证方式是 AcceptUsersAuthenticationHandler (老版本好像是SimpleTestUsernamePasswordAuthenticationHandler),默认用户名/密码为 casuser/Mellon(cas/WEB-INF/deployerConfigContext.xml 中找到 id=primaryAuthenticationHandler
的bean查看,里面的map也可以自己增加更多个)。我们通常需要从数据库中取出用户名和密码进行验证,所以我们需要修改 deployerConfigContext.xml,配置我们自己的服务认证方式。
虽然 CAS Server 已经部署成功,但这只是一个缺省的实现,在实际使用的时候,还需要根据实际概况做扩展和定制,最主要的是扩展认证 (Authentication) 接口和 CAS Server 的界面。
7. 扩展认证接口
CAS Server 负责完成对用户的认证工作,它会处理登录时的用户凭证 (Credentials) 信息,用户名/密码对是最常见的凭证信息。CAS Server 可能需要到数据库检索一条用户帐号信息,也可能在 XML 文件中检索用户名/密码,还可能通过 LDAP Server 获取等,在这种情况下,CAS 提供了一种灵活但统一的接口和实现分离的方式,实际使用中 CAS 采用哪种方式认证是与CAS的基本协议分离开的,用户可以根据认证的接口去定制和扩展。
扩展 AuthenticationHandler
CAS 提供扩展认证的核心是 AuthenticationHandler 接口,该接口定义如清单 1 下:
清单 1. AuthenticationHandler定义
public interface AuthenticationHandler { /** * Method to determine if the credentials supplied are valid. * @param credentials The credentials to validate. * @return true if valid, return false otherwise. * @throws AuthenticationException An AuthenticationException can contain * details about why a particular authentication request failed. */ boolean authenticate(Credentials credentials) throws AuthenticationException; /** * Method to check if the handler knows how to handle the credentials * provided. It may be a simple check of the Credentials class or something * more complicated such as scanning the information contained in the * Credentials object. * @param credentials The credentials to check. * @return true if the handler supports the Credentials, false othewrise. */ boolean supports(Credentials credentials); }
该接口定义了 2 个需要实现的方法,supports ()方法用于检查所给的包含认证信息的Credentials 是否受当前 AuthenticationHandler 支持;而 authenticate() 方法则担当验证认证信息的任务,这也是需要扩展的主要方法,根据情况与存储合法认证信息的介质进行交互,返回 boolean 类型的值,true 表示验证通过,false 表示验证失败。
CAS3中还提供了对AuthenticationHandler 接口的一些抽象实现,比如,可能需要在执行authenticate() 方法前后执行某些其他操作,那么可以让自己的认证类扩展自清单 2 中的抽象类:
清单 2. AbstractPreAndPostProcessingAuthenticationHandler定义
public abstract class AbstractPreAndPostProcessingAuthenticationHandler implements AuthenticateHandler{ protected Log log = LogFactory.getLog(this.getClass()); protected boolean preAuthenticate(final Credentials credentials) { return true; } protected boolean postAuthenticate(final Credentials credentials, final boolean authenticated) { return authenticated; } public final boolean authenticate(final Credentials credentials) throws AuthenticationException { if (!preAuthenticate(credentials)) { return false; } final boolean authenticated = doAuthentication(credentials); return postAuthenticate(credentials, authenticated); } protected abstract boolean doAuthentication(final Credentials credentials) throws AuthenticationException; }AbstractPreAndPostProcessingAuthenticationHandler 类新定义了 preAuthenticate() 方法和 postAuthenticate() 方法,而实际的认证工作交由 doAuthentication() 方法来执行。因此,如果需要在认证前后执行一些额外的操作,可以分别扩展 preAuthenticate()和 ppstAuthenticate() 方法,而 doAuthentication() 取代 authenticate()
成为了子类必须要实现的方法。
由于实际运用中,最常用的是用户名和密码方式的认证,CAS3 提供了针对该方式的实现,如清单 3 所示:
清单 3. AbstractUsernamePasswordAuthenticationHandler 定义
public abstract class AbstractUsernamePasswordAuthenticationHandler extends AbstractPreAndPostProcessingAuthenticationHandler{ ... protected final boolean doAuthentication(final Credentials credentials) throws AuthenticationException { return authenticateUsernamePasswordInternal((UsernamePasswordCredentials) credentials); } protected abstract boolean authenticateUsernamePasswordInternal( final UsernamePasswordCredentials credentials) throws AuthenticationException; protected final PasswordEncoder getPasswordEncoder() { return this.passwordEncoder; } public final void setPasswordEncoder(final PasswordEncoder passwordEncoder) { this.passwordEncoder = passwordEncoder; } ... }
基于用户名密码的认证方式可直接扩展自 AbstractUsernamePasswordAuthenticationHandler,验证用户名密码的具体操作通过实现 authenticateUsernamePasswordInternal() 方法达到,另外,通常情况下密码会是加密过的,setPasswordEncoder() 方法就是用于指定适当的加密器。
从以上清单中可以看到,doAuthentication() 方法的参数是 Credentials 类型,这是包含用户认证信息的一个接口,对于用户名密码类型的认证信息,可以直接使用 UsernamePasswordCredentials,如果需要扩展其他类型的认证信息,需要实现Credentials接口,并且实现相应的 CredentialsToPrincipalResolver 接口,其具体方法可以借鉴 UsernamePasswordCredentials 和 UsernamePasswordCredentialsToPrincipalResolver。
8.实现JDBC的认证
用户的认证信息通常保存在数据库中,因此本文就选用这种情况来介绍。将前面下载的 cas-server-{version}-release.zip 包解开后,在 modules 目录下可以找到包 cas-server-support-jdbc-{version}.jar,其提供了通过 JDBC 连接数据库进行验证的缺省实现,基于该包的支持,我们只需要做一些配置工作即可实现 JDBC 认证。
JDBC 认证方法支持多种数据库,DB2, Oracle, MySql, Microsoft SQL Server 等均可,这里以Mysql作为例子介绍。并且假设Mysql数据库名:test,数据库登录用户名: root,数据库登录密码:password,用户信息表为: t_user,该表包含用户名和密码的两个数据项分别为 username 和 password。用户表数据如下图所示:
1)配置DataSource
打开文件 cas/WEB-INF/deployerConfigContext.xml,添加一个新的 bean 标签,以MYSQL为例,内容如清单 4 所示:
<!-- Data source definition --> <bean id="casDataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName"> <value>com.mysql.jdbc.Driver</value> </property> <property name="url"> <value>jdbc:mysql://localhost:3306/test</value> </property> <property name="username"> <value>root</value> </property> <property name="password"> <value>passw0rd</value> </property> </bean>其中 casDataSource 在后面配置 AuthenticationHandler 会被引用,添加数据库驱动程序、连接地址、数据库登录用户名以及登录密码。
2)配置 AuthenticationHandler
CAS 4.0.0 提供了 3 个基于 JDBC 的 AuthenticationHandler,分别为 BindModeSearchDatabaseAuthenticationHandler, QueryDatabaseAuthenticationHandler, SearchModeSearchDatabaseAuthenticationHandler。
- BindModeSearchDatabaseAuthenticationHandler 是用所给的用户名和密码去建立数据库连接,根据连接建立是否成功来判断验证成功与否;
- QueryDatabaseAuthenticationHandler 通过配置一个 SQL 语句查出密码,与所给密码匹配;
- SearchModeSearchDatabaseAuthenticationHandler 通过配置存放用户验证信息的表、用户名字段和密码字段,构造查询语句来验证。
使用哪个 AuthenticationHandler,需要在 deployerConfigContext.xml 中设置,默认情况下,CAS 4.0.0 使用 AcceptUsersAuthenticationHandler(上面已经提到,需要在 deployerConfigContext.xml 中查看)。
在 deployerConfigContext.xml 文件中可以找到如下配置:
<bean id="primaryAuthenticationHandler" class="org.jasig.cas.authentication.AcceptUsersAuthenticationHandler"> <property name="users"> <map> <entry key="casuser" value="Mellon"/> </map> </property> </bean>
这里我们注释掉这段配置,然后换成我们希望的一个 AuthenticationHandler,比如,使用QueryDatabaseAuthenticationHandler 或 SearchModeSearchDatabaseAuthenticationHandler 可以分别选取清单 5 或清单 6 的配置。
清单 5. 使用 QueryDatabaseAuthenticationHandler
<bean id="primaryAuthenticationHandler" class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler"> <property name="dataSource" ref="casDataSource" /> <property name="sql" value="select password from t_user where lower(username) = lower(?)" /> <!-- 指定密码加密器(可选) --> <!-- <property name="passwordEncoder" ref="passwordEncoder" /> --> </bean>清单 6. 使用 SearchModeSearchDatabaseAuthenticationHandler
<bean id="SearchModeSearchDatabaseAuthenticationHandler" class="org.jasig.cas.adaptors.jdbc.SearchModeSearchDatabaseAuthenticationHandler" abstract="false" singleton="true" lazy-init="default" autowire="default" dependency-check="default"> <property name="tableUsers"> <value>userTable</value> </property> <property name="fieldUser"> <value>userName</value> </property> <property name="fieldPassword"> <value>password</value> </property> <property name="dataSource" ref="casDataSource " /> </bean>另外,由于存放在数据库中的密码通常是加密过的,所以 AuthenticationHandler 在匹配时需要知道使用的加密方法,在 deployerConfigContext.xml 文件中我们可以为具体的 AuthenticationHandler 类配置一个 property,指定加密器类,比如对于 QueryDatabaseAuthenticationHandler,可以修改如清单7所示:
清单 7. QueryDatabaseAuthenticationHandler配置加密器类
<!-- 密码加密器(可以指定自己实现的加密器) --> <bean id="passwordEncoder" class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder" > <constructor-arg name="encodingAlgorithm" value="MD5"/> <property name="characterEncoding" value="UTF-8"/> </bean>本文这里由于未对数据库中的用户数据进行加密,所以在清单5中将配置的加密属性注释掉。
注意:DataSource 依赖于 commons-collections-3.2.jar、commons-dbcp-1.2.1.jar、commons-pool-1.3.jar、数据库驱动包、cas对jdbc的支持包cas-server-support-jdbc-4.0.0.jar,需要找到这几个jar包放进 %TOMCAT_HOME%/webapps/cas/WEB-INF/lib 目录。
然后便可以启动Tomcat使用数据库中的用户名和密码进行登录测试了。
注意:DataSource 依赖于 commons-collections-3.2.jar、commons-dbcp-1.2.1.jar、commons-pool-1.3.jar、数据库驱动包、cas对jdbc的支持包cas-server-support-jdbc-4.0.0.jar,需要找到这几个jar包放进 %TOMCAT_HOME%/webapps/cas/WEB-INF/lib 目录。
然后便可以启动Tomcat使用数据库中的用户名和密码进行登录测试了。
9.部署CAS客户端应用
单点登录的目的是为了让多个相关联的应用使用相同的登录过程,本文在讲解过程中构造 2个简单的应用,分别以 CASClient1 和 CASClient2 来作为示例,它们均只有一个页面,显示欢迎信息和当前登录用户名。这两个应用使用同一套登录信息,并且只有登录过的用户才能访问,通过本文的配置,实现单点登录,即只需登录一次就可以访问这两个应用。应用的工程结构很简单,引入必要的jar包,然后新建一个index.jsp页面。
index.jsp代码清单
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>CASClient1's index.jsp</title> </head> <body> <% /*获取登录用户名*/ String username = request.getRemoteUser(); %> current user: <%=username %> <p><a href="https://localhost:8443/cas/logout">logout</a></p> </body> </html>
10.配置CAS客户端Filter
在CAS的client端的web.xml文件中配置过滤器如下:
<!-- 该过滤器用于实现单点登出功能,可选配置。 -->
<!-- 登出地址 https://casserver:8443/cas/logout -->
<filter>
<filter-name>CAS Single Sign Out Filter</filter-name>
<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
</filter>
<!-- 该过滤器负责用户的认证工作,必须启用它 -->
<filter>
<filter-name>CAS Authentication Filter</filter-name>
<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
<init-param>
<param-name>casServerLoginUrl</param-name>
<param-value>https://localhost:8443/cas/login</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>http://localhost:8080</param-value>
</init-param>
</filter>
<!-- 该过滤器负责对Ticket的校验工作,必须启用它 -->
<filter>
<filter-name>CAS Validation Filter</filter-name>
<filter-class>org.jasig.cas.client.validation.Cas10TicketValidationFilter</filter-class>
<init-param>
<param-name>casServerUrlPrefix</param-name>
<param-value>https://localhost:8443/cas</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>http://localhost:8080</param-value>
</init-param>
<init-param>
<param-name>redirectAfterValidation</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<!-- 该过滤器负责实现HttpServletRequest请求的包装, 比如允许开发者通过HttpServletRequest的getRemoteUser()方法获得SSO登录用户的登录名,可选配置。 -->
<filter>
<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
<filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
</filter>
<!-- 该过滤器使得开发者可以通过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 Single Sign Out Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS Authentication Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS Validation Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS Assertion Thread Local Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>
运行Client工程,首次访问任一页面就会跳转到https://localhost:8443/cas/login进行认证。
把你的退出链接设置为:https://localhost:8443/cas/logout 即可实现单点登出,如果需要在系统退出后返回指定页面,我们可以修改源码在logout后面增加参数来实现。
11.单点登录测试同时运行CAS server、 CASClient1 和CASClient2。分别访问下面的URL:
CASClient1:
localhost:8080/CASClient1/index.jsp
CASClient2: localhost:8080/CASClient2/index.jsp
当第一次访问上面的URL时,会重定向到下面的页面:
这时输入数据库中的用户名和对应的密码登录,登录成功后会看到如下页面:
此时访问第二个URL发现index页面会直接打开,而不用再次登录,因为访问CASClient1的时候已经认证过了。这就实现了所谓的单点登录。
相关文章推荐
- java-模拟tomcat服务器
- i-jetty环境搭配与编译
- 实现单Tomcat多Server配置
- 生产环境下的Tomcat配置
- Linux部署Tomcat服务器
- jenkins------结合maven将svn项目自动部署到tomcat下
- 如何搞定tomcat这只喵~
- tomcat在opensuse下开机自启失败的原因分析及解决方法
- jsp项目中更改tomcat的默认index.jsp访问路径的方法
- Tomcat 多端口 多应用
- tomcat 5.0 + apache 2.0 完全安装步骤详解
- Tomcat安全设置 win2003 下tomcat权限限制
- Jsp和PHP共用80端口整合Apache和Tomcat(访问时无需加端口号)
- Tomcat服务器 安全设置第1/3页
- tomcat 6.0.20在一个机器上安装多个服务的方法
- Tomcat 5.5 数据库连接池配置
- Tomcat内存溢出分析及解决方法
- apache tomcat 一个网站多域名的实现方法
- Tomcat无法加载css和js等静态资源文件的解决思路