单点登陆前奏

1.单点登陆认识及环境搭建

1.单点登陆(Single Sign On)

简称SSO。定义是在多个应用系统中,用户只须要登陆一次就能够访问全部互相信任的应用系统。通常用于公司内部产品或某个产品系列的全部子系统中。好比公司的oa系统、icode系统、邮箱系统等等;再好比豆瓣系列的豆瓣FM、豆瓣读书、豆瓣电影、豆瓣日记等等,只须要登陆一次,访问其余系统就没有必要再登陆了。html

背景:java

  1. 公司内部现存系统较多,各个系统分布在不一样服务器上,用户使用过程当中须要屡次重复登录,使用麻烦
  2. 各系统实现技术不相同,但都是基于Web,客户端语言能够是非java语言
  3. 各个系统用户数据不尽相同,缺少统一管理,用户须要维护多套密码,管理员也须要维护多套用户信息
  4. SSO服务端仅负责认证,权限管理能够交由各系统本身完成

想了解更多单点登陆原理进入单点登陆原理与简单实现【转】web

2.建立证书

证书是单点登陆认证系统中很重要的一把钥匙,客户端与服务器的交互安全靠的就是证书;本次因为是演示因此就用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"

3.Tomcat配置

启用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:建立证书时的密码

4. 配置www.wp.com域名指向本地


编辑host文件,添加下面内容,保存便可。

5.启动tomcat,浏览器输入https:www.wp.com:8443/ 是否正常访问

若是正常访问到该地址,那么表示配置成功。

若还不能访问,则在server.xml中将下面内容注释掉。

<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />

2.单点登陆实现

1.服务端cas-server

下载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默认的验证规则是只要用户名和密码相同就能够经过。

2.客户端

新建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

输入用户名和密码,回车

3.单点登陆流程解析

1.理解几个概念

一、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是随机生成的,具备不可伪造性

2.流程图及流程解析

单点登陆经常使用的操做有三个: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改造是颇有必要了解的。

相关文章
相关标签/搜索