简称SSO。定义是在多个应用系统中,用户只须要登陆一次就能够访问全部互相信任的应用系统。通常用于公司内部产品或某个产品系列的全部子系统中。好比公司的oa系统、icode系统、邮箱系统等等;再好比豆瓣系列的豆瓣FM、豆瓣读书、豆瓣电影、豆瓣日记等等,只须要登陆一次,访问其余系统就没有必要再登陆了。html
背景:java
- 公司内部现存系统较多,各个系统分布在不一样服务器上,用户使用过程当中须要屡次重复登录,使用麻烦
- 各系统实现技术不相同,但都是基于Web,客户端语言能够是非java语言
- 各个系统用户数据不尽相同,缺少统一管理,用户须要维护多套密码,管理员也须要维护多套用户信息
- SSO服务端仅负责认证,权限管理能够交由各系统本身完成
想了解更多单点登陆原理进入单点登陆原理与简单实现【转】web
证书是单点登陆认证系统中很重要的一把钥匙,客户端与服务器的交互安全靠的就是证书;本次因为是演示因此就用JDK自带的keytool工具生成证书;若是之后真正在产品环境中使用确定要去证书提供商去购买,证书认证通常都是由VeriSign认证,中文网站:http://www.verisign.com/cn/spring
JDK自带的keytool工具生成证书过程以下:
注意:以管理员的身份打开cmd数据库
1.生成证书apache
keytool -genkey -alias tomcat -keyalg RSA -keystore D:/software/keys/keystore
须要设置密码:这里设置成123456
浏览器
注:www.wp.com是域名,之后配置CAS客户端时须要用到且必须一致。缓存
2.导出证书tomcat
keytool -export -trustcacerts -alias tomcat -file D:/software/keys/tomcat.cer -keystore D:/software/keys/keystore
3.将证书导入JDK信任库安全
keytool -import -trustcacerts -alias tomcat -file D:/software/keys/tomcat.cer -keystore "D:\Program Files\Java\jdk1.8.0_131\jre\lib\security/cacerts"
密码是默认的changeit,而不是以前设置的密码。
https://www.cnblogs.com/hamfy/archive/2012/07/31/2616805.html
4.其余命令
查看证书列表
keytool -list -v -keystore "D:\Program Files\Java\jdk1.8.0_131\jre\lib\security/cacerts"
删除证书
keytool -delete -trustcacerts -alias tomcat -keystore "D:\Program Files\Java\jdk1.8.0_131\jre\lib\security/cacerts"
启用We服务器的SSL,也就是HTTPS加密协议。
配置tomcat的server.xml
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" keystoreFile="D:/software/keys/keystore" keystorePass="123456" />
keystoreFile:建立的key存放的位置
keystorePass:建立证书时的密码
编辑host文件,添加下面内容,保存便可。
若是正常访问到该地址,那么表示配置成功。
若还不能访问,则在server.xml中将下面内容注释掉。
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
下载cas-server-3.5.0-release
https://www.apereo.org/projects/cas/news
下载完成后解压,并更名为cas,复制到tomcat/webapp目录下,启动tomcat,并访问地址:
https:www.wp.com:8443/cas/login 用户名/密码:admin/admin点击登陆。cas默认的验证规则是只要用户名和密码相同就能够经过。
新建springboot web项目,使用maven管理jar包,pom.xml文件加入包
<dependencies> <!--web应用基本环境配置 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.jasig.cas.client</groupId> <artifactId>cas-client-core</artifactId> <version>${cas.version}</version> </dependency> </dependencies>
application.yaml配置文件
server: port: 8081 spring: profiles: active: dev --- # 开发环境配置 spring: profiles: dev cas: casServerUrlPrefix: https://www.wp.com:8443/cas casServerLoginUrl: https://www.wp.com:8443/cas/login serverName: http://localhost:8081 encoding: UTF-8 urlPatterns: /*
新建一个配置类,配置单点登陆客户端过滤器CasConfig
package com.baidu.bpit.uuap.conf; import org.jasig.cas.client.authentication.AuthenticationFilter; import org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter; import org.springframework.boot.context.embedded.FilterRegistrationBean; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration @ConfigurationProperties(prefix = "cas", ignoreUnknownFields = true) public class CasConfig { private String casServerUrlPrefix; // sso验证地址 private String casServerLoginUrl; // sso登陆地址 private String serverName; // sso验证或者登录后返回的地址 private String urlPatterns; // sso过滤匹配 private String encoding; // sso编码 /** * 注册CAS SSO 验证用户是否存在Filter * * @return */ @Bean public FilterRegistrationBean cas20ValidateRegistration() { FilterRegistrationBean cas20 = new FilterRegistrationBean(); cas20.setFilter(new Cas20ProxyReceivingTicketValidationFilter()); cas20.addUrlPatterns(urlPatterns); cas20.addInitParameter("casServerUrlPrefix", casServerUrlPrefix); cas20.addInitParameter("serverName", serverName); cas20.addInitParameter("encoding", encoding); return cas20; } /** * 注册CAS SSO 用户登陆Filter * * @return */ @Bean public FilterRegistrationBean cas20LoginRegistration() { FilterRegistrationBean cas20 = new FilterRegistrationBean(); cas20.setFilter(new AuthenticationFilter()); cas20.addUrlPatterns(urlPatterns); cas20.addInitParameter("casServerLoginUrl", casServerLoginUrl); cas20.addInitParameter("serverName", serverName); cas20.addInitParameter("encoding", encoding); return cas20; } public String getCasServerUrlPrefix() { return casServerUrlPrefix; } public void setCasServerUrlPrefix(String casServerUrlPrefix) { this.casServerUrlPrefix = casServerUrlPrefix; } public String getCasServerLoginUrl() { return casServerLoginUrl; } public void setCasServerLoginUrl(String casServerLoginUrl) { this.casServerLoginUrl = casServerLoginUrl; } public String getServerName() { return serverName; } public void setServerName(String serverName) { this.serverName = serverName; } public String getUrlPatterns() { return urlPatterns; } public void setUrlPatterns(String urlPatterns) { this.urlPatterns = urlPatterns; } public String getEncoding() { return encoding; } public void setEncoding(String encoding) { this.encoding = encoding; } }
建立访问首页controller,获取到session中的用户心
@ResponseBody @RequestMapping("/demo") public String getLoginUser(HttpServletRequest httpServletRequest) { // 获取session里面的用户信息 HttpSession session = httpServletRequest.getSession(); String userName = "-"; if (null != session) { Assertion assertion = (Assertion) session.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION); if (null != assertion) { userName = assertion.getPrincipal().getName(); } } logger.info("get current user: {}", userName); return "Welcome you : " + "demo2"; }
而后启动项目,浏览器访问http://localhost:8081/demo
输入用户名和密码,回车
一、TGC (Ticket-granting cookie):存放用户身份认证凭证的cookie,在浏览器和SSO server之间通信时使用,而且只能用HTTPS传输,说白了,就是你登录SSO系统后,SSO server会在你的浏览器Cookie里面植入一段Cookie,这样在Cookie的有效期内你访问任何接入SSO的系统都不须要再次输入密码,只须要校验该Cookie的有效性,由于基于HTTPS传输,因此说可以保证传输过程当中的安全性,可是注意保管你本身电脑的不被别人窃取该信息,否则别人就能伪造以你的身份登录。也称为全局会话。
查看你的cookie就能看到该信息,就是叫CASTGC的cookie,能够看到该cookie的有效期为浏览会话结束时。能够设置一个月时间。
二、TGT(Ticket Granting ticket):票据受权票据。该票据存在Server端,其实TGC是TGT的id而已,在你完成认证后服务端生成TGT存起来,而后把TGT的id下发给用户保存在cookie中,这样下次用户来就能够经过TGC找到TGT,而后校验该TGT的一系列信息,认证经过就能够免密码登陆。
三、ST(Service Ticket):这个ST即是浏览器中的ticket参数,sso认证经过后携带该参数让用户重定向到下游系统,下游系统拿到该参数便去sso server验证该参数的有效性,经过验证即可以让用户进入下游系统。
怎样才能保证ticket参数的安全性呢?
(1)、https传输。
(2)、ticket只能使用一次,无论认证成功或者失败
(3)、ticket有有效期,默认5分钟
(4)、ticket是随机生成的,具备不可伪造性
单点登陆经常使用的操做有三个:login、serviceValidate、logout,最复杂的就是login接口。
单点登陆服务端使用spring-webflow技术实现了单点登陆的login流程,整理login逻辑流程图以下:
1.用户访问系统1的受保护资源,系统1发现用户未登陆,跳转到SSO认证中心,并将用户访问系统1的地址做为参数传递过去
2.SSO认证中心接收到请求后,走login-webflow流程,配置信息在cas-servlet.xml中,
首先会进入初始化操做流程 initialFlowSetupAction,执行初始化数据等操做。
而后响应给浏览器casLoginView.jsp页面
用户提交用户名和密码后去SSO认证中心校验
校验success后,去生成全局会话,将id保存到cookie中;sendTicketGrantingTicketAction
而后去建立系统1的受权令牌ticket;generateServiceTicketAction
最后,SSO以以前传过来的参数地址为地址而且拼接ticket参数,重定向到系统1中。
系统1拿到ticket参数后,去SSO认证中心校验ticket的有效性,有效,再重定向到系统1,系统1会创建用户和系统1的局部会话,证实用户是否登陆系统1,最后返回系统1访问的资源。
注意:全局会话TGT的id TGC保存在cookie中CASTGC;若该cookie存在,那么其余客户端也是登陆状态,不会再验证用户密码信息了,而后生成新的ticket。
ticket完成客户端service在SSO认证中心的校验。
cas client、cas server、浏览器之间的流程
在图中第3步用户认证成功后,cas server会生成Ticket Granting Ticket(票据受权票据,简称TGT),同时将TGT值以CASTGC为名保存到浏览器的cookie中,以后生成Service Ticket(服务票据,简称ST)并缓存,在第4步时将ST经过浏览器重定向的URL传给cas client。
当客户访问另外一个cas client时,一样会被重定向到cas server,而此时咱们并不但愿再次让用户输入用户密码登录,名为CASTGC的cookie这时就体现出做用来了,cas server发现存在名为CASTGC的cookie就将其值在已保存的TGT中查找,若存在,则说明已存在合法的TGT,cas server就根据该TGT生成新的ST,接下来的流程就和之前同样了。
固然,在实际产品中不能直接使用从官网下载下来的cas-server,须要对其进行相关的改造,好比登录页面须要改为体现产品特点的,添加验证码,用户登陆信息验证方案,TGT、serviceTicket缓存方案和持久化到数据库、加入域登陆等等诸多地方。那么下一篇单点登陆cas-server改造是颇有必要了解的。