本文内容目录
cas介绍
tomcat配置https支持(包括证书生成步骤)
cas服务端搭建
cas客户端搭建
1. cas介绍
简介:
CAS是Central Authentication Service的缩写,中央认证服务,一种独立开放指令协议。CAS 是 耶鲁大学(Yale University)发起的一个开源项目,旨在为 Web 应用系统提供一种可靠的单点登录方法,CAS 在 2004 年 12 月正式成为 JA-SIG 的一个项目。
特点:
1、开源的企业级单点登录解决方案。
2、CAS Server 为需要独立部署的 Web 应用。
3、CAS Client 支持非常多的客户端(这里指单点登录系统中的各个 Web 应用),包括 Java, .Net, PHP, Perl, Apache, uPortal, Ruby 等。
4、CAS属于Apache 2.0许可证,允许代码修改,再发布(作为开源或商业软件)。
从结构上看,CAS 包含两个部分: CAS Server 和 CAS Client。CAS Server 需要独立部署,主要负责对用户的认证工作;CAS Client 负责处理对客户端受保护资源的访问请求,需要登录时,重定向到 CAS Server。下图 是 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 官方网站上的相关文档。
2. tomcat配置https支持(包括证书生成步骤)
CAS采用HTTPS协议处理用户请求,所以我们需要配置Tomcat支持HTTPS协议:
第一步:https请求需要证书,我采用JDK自带的keytool工具生成秘钥库:
JDK自带的keytool工具生成秘钥库请参考我这篇文章
第二步:tomcat支持https请求
tomcat支持https请求请参考我这篇文章
3. cas服务端搭建
cas服务端war包下载地址:
点击官网下载
点击百度网盘提取 提取码:1bm9
把war包放tomcat下,启动tomcat会自动解压,我们把名称改成cas,方便访问
修改cas服务端日志文件生成位置:
用户名:casuser
密码:Mellon
(初始的账号密码)
配置数据源,数据库用户认证
第一步:新建数据和表:
DROP TABLE IF EXISTS `my_cas`; CREATE TABLE `my_cas` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(30) DEFAULT NULL, `password` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; insert into `my_cas`(`id`,`username`,`password`) values (1,'admin','123456');
第二步:修改cas配置文件,配置自定义的用户表,以及用户密码MD5加密
先注释掉原来默认的用户名密码
修改: tomcat/webapps/cas/WEB-INF/classes/application.properties
#CAS Authentication Credentials #cas.authn.accept.users=casuser::Mellon cas.authn.jdbc.query[0].url=jdbc:mysql://ip:3306/test_cas?serverTimezone=GMT cas.authn.jdbc.query[0].user=root cas.authn.jdbc.query[0].password=123456 cas.authn.jdbc.query[0].sql=select * from my_cas where username=? cas.authn.jdbc.query[0].fieldPassword=password cas.authn.jdbc.query[0].driverClass=com.mysql.jdbc.Driver cas.authn.jdbc.query[0].passwordEncoder.type=DEFAULT cas.authn.jdbc.query[0].passwordEncoder.characterEncoding=UTF-8 #MD5加密策略 cas.authn.jdbc.query[0].passwordEncoder.encodingAlgorithm=MD5 cas.tgc.secure=false cas.serviceRegistry.initFromJson=true
注意:修改好后用户表里password存的应该是加密后的
数据库生成下md5密码
SELECT MD5('123456');
第三步:放入mysql驱动jar包,放入位置:tomcat\webapps\cas\WEB-INF\lib
点击百度网盘提取 提取码:1bm9
至此,cas服务端已经搭建完毕。
4. cas客户端搭建
本文介绍两个例子,均实践成功,分别是springBoot整合cas客户端和ssm整合cas客户端
两种方式都需在pom中添加cas客户端依赖
org.jasig.cas.client cas-client-core 3.4.1
1.springBoot整合cas客户端
项目中添加cas配置类
package tca.xxx.xxx.cas; import org.jasig.cas.client.session.SingleSignOutFilter; import org.jasig.cas.client.session.SingleSignOutHttpSessionListener; import org.jasig.cas.client.util.AssertionThreadLocalFilter; import org.jasig.cas.client.util.HttpServletRequestWrapperFilter; import org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.ServletListenerRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @Configuration @Component @PropertySource({"classpath:common.properties"}) public class CasConfigure{ /** * cas服务端地址 https://ip:8443/cas */ @Value("${casServicePath}") private String casServerLoginUrl; /**lo * 当前应用地址 你自己项目访问地址 */ @Value("${myServicePath}") private String serverName; /** * 该监听器用于实现单点登出功能,session失效监听器 */ @Bean public ServletListenerRegistrationBeansingleSignOutHttpSessionListener() { ServletListenerRegistrationBean listener = new ServletListenerRegistrationBean<>(); listener.setEnabled(true); listener.setListener(new SingleSignOutHttpSessionListener()); listener.setOrder(1); return listener; } /** * 该过滤器用于实现单点登出功能,当一个系统登出时,cas服务端会通知,各个应 * 用进行进行退出操作,该过滤器就是用来接收cas回调的请求,如果是前后端分离 * 应用,需要重写SingleSignOutFilter过滤器,按自已的业务规则去处理 */ @Bean public FilterRegistrationBean singleSignOutFilter() { FilterRegistrationBean filterRegistration = new FilterRegistrationBean(); filterRegistration.setFilter(new SingleSignOutFilter()); //filterRegistration.setEnabled(true); filterRegistration.addUrlPatterns("/*"); filterRegistration.addInitParameter("casServerUrlPrefix", casServerLoginUrl); filterRegistration.setOrder(2); return filterRegistration; } /** * 该过滤器负责单点登录功能,用户登录的认证工作 * @return */ @Bean public FilterRegistrationBean authenticationFilterRegistrationBean() { FilterRegistrationBean authenticationFilter = new FilterRegistrationBean(); authenticationFilter.setFilter(new MyAuthenticationFilter()); //这里就是被换的类 Map initParameters = new HashMap (); initParameters.put("casServerLoginUrl", casServerLoginUrl); initParameters.put("ignorePattern", "/logout/success|/index"); initParameters.put("serverName",serverName); authenticationFilter.setInitParameters(initParameters); authenticationFilter.setOrder(3); return authenticationFilter; } /** * 该过滤器用于单点登录功能,负责对Ticket的校验工作 * @return */ @Bean public FilterRegistrationBean ValidationFilterRegistrationBean(){ FilterRegistrationBean authenticationFilter = new FilterRegistrationBean(); authenticationFilter.setOrder(4); authenticationFilter.setFilter(new Cas20ProxyReceivingTicketValidationFilter()); Map initParameters = new HashMap<>(); initParameters.put("casServerUrlPrefix", casServerLoginUrl); initParameters.put("serverName", serverName); initParameters.put("redirectAfterValidation", "true"); initParameters.put("useSession", "true"); initParameters.put("authn_method", "mfa-duo"); authenticationFilter.setInitParameters(initParameters); List urlPatterns = new ArrayList (); urlPatterns.add("/*"); authenticationFilter.setUrlPatterns(urlPatterns); return authenticationFilter; } /** * 该过滤器用于单点登录功能 ,对HttpServletRequest请求包装, 可通过HttpServletRequest的getRemoteUser()方法获得登录用户的登录名 * @return */ @Bean public FilterRegistrationBean casHttpServletRequestWrapperFilter(){ FilterRegistrationBean authenticationFilter = new FilterRegistrationBean(); authenticationFilter.setFilter(new HttpServletRequestWrapperFilter()); authenticationFilter.setOrder(5); List urlPatterns = new ArrayList (); urlPatterns.add("/*"); authenticationFilter.setUrlPatterns(urlPatterns); return authenticationFilter; } /** * 该过滤器使得可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。 比如AssertionHolder.getAssertion().getPrincipal().getName()。 这个类把Assertion信息放在ThreadLocal变量中,这样应用程序不在web层也能够获取到当前登录信息 * @return */ @Bean public FilterRegistrationBean casAssertionThreadLocalFilter(){ FilterRegistrationBean authenticationFilter = new FilterRegistrationBean(); authenticationFilter.setFilter(new AssertionThreadLocalFilter()); authenticationFilter.setOrder(6); List urlPatterns = new ArrayList (); urlPatterns.add("/*"); authenticationFilter.setUrlPatterns(urlPatterns); return authenticationFilter; } }
根据自己的需求逻辑编写自己的MyAuthenticationFilter类,此类在重写AuthenticationFilter基础上,再根据自己需求修改即可。注:无特殊需求上述配置中 “authenticationFilter.setFilter(new MyAuthenticationFilter()); //这里就是被换的类” 这段配置MyAuthenticationFilter()用默认的AuthenticationFilter()即可。
单点登出
/** * 单点登出 * @return */ @RequestMapping("/logout") public String logout(HttpServletRequest request){ return "redirect:https://ip:8443/cas/logout"; }
2.ssm整合cas客户端
在web.xml中添加cas客户端相关配置 注:https://10.0.0.101:8447/gatewayMassage/为ssm项目访问地址
org.jasig.cas.client.session.SingleSignOutHttpSessionListener CAS Single Sign Out Filter org.jasig.cas.client.session.SingleSignOutFilter casServerUrlPrefix https://ip:8443/cas CAS Single Sign Out Filter /* CAS Authentication Filter org.jasig.cas.client.authentication.AuthenticationFilter casServerLoginUrl https://ip:8443/cas/login serverName https://10.0.0.101:8447/gatewayMassage/ ignorePattern /logout/success|/index CAS Validation Filter org.jasig.cas.client.validation.Cas30ProxyReceivingTicketValidationFilter casServerUrlPrefix https://ip:8443/cas serverName https://10.0.0.101:8447/gatewayMassage/ redirectAfterValidation true useSession true authn_method mfa-duo CAS HttpServletRequest Wrapper Filter org.jasig.cas.client.util.HttpServletRequestWrapperFilter CAS Single Sign Out Filter /* CAS Validation Filter /* CAS Authentication Filter /* CAS HttpServletRequest Wrapper Filter /* CAS Assertion Thread Local Filter org.jasig.cas.client.util.AssertionThreadLocalFilter CAS Assertion Thread Local Filter /*