# 架构演进 for SSO

常见架构(下图)

  • RPC子系统提供 内网 服务
  • Web Sever 集群提供,作为消费者,提供api接口
  • redis 缓存



认证信息(session)被web管理。无法sso

需要一个sso单点登录服务器(替代了原先的 session 认证),为 sso 服务器配置用户数据库

但这样只能认证不能授权,(上图)

因此,认证之后,为了授权,还需要有服务器存储授权信息(下图)

而为了让子系统也能访问,需要把授权信息放缓存里面(redis)

sso设计过程之中,Redis缓存数据库将保存用户与权限信息,这样就可以避免重复的进行角色与权限数据的查询处理了

<mark>重点</mark>。同时,为了保证安全性需要使用 https 访问,以及证书的签发,才能够正常使用 SSO

(下图)

证书概念:

  • CA证书
  • 服务器证书
  • 客户端证书

# 认识 https

HTTPS:HTTP + SSL 或者 HTTP + TLS

  • HTTP (HyperText Transfer Protocol) 超文本传输协议
    是一种详细规定了浏览器和www服务器之间相互通信的规则,

  • SSL(Secure Sockets Layer) 安全套接字层
    HTTPS的安全基础,https传输内容通过 SSL 加密

  • TLS(Transport Layer Security) 传输层安全协议

TCP五层模型 和 OSI七层模型

两者区别:

  • https协议需要到 Ca 申请证书,一般免费证书很少,需要交费。
  • http是明文传输,https通过ssl加密
  • http端口80,https端口443

锁,有ca证书
https,安全协议


## 为什么 不能 http

正常流程(下图)

黑客伪造表单(下图)

用如 HttpClient 可以伪造表单

黑客拦截(下图)

给用户植入拦截程序,用户数据全部被拦截。(并且数据用明文传递)


## HTTP 报文组成

HTTP报文是由一行行简单字符串组成的,是纯文本,可以很方便地对其进行读写。

## 如何保护 HTTP 传输的安全?

  • 服务器认证(客户端需要明确的知道在与可靠的服务器通信)
  • 客户端认证(服务器明确与真正的客户通讯)
  • 完整性(客户端与服务器端的数据不会被篡改)
  • 加密(客户端与服务器采用私密交流)
  • 效率(执行速度更快的算法,使客户端与服务器端都可以快速处理)
  • 普适***器端与客户端都支持的协议)
  • 管理的可扩展性(安全访问不受区域位置的限制)
  • 适应性(适应当前流行的安全操作)

# SSL 和 TLS

SSL可以理解为最初进行加密的协议,而TLS是在SSL之后产生的,可以理解为前者的补充版。

## SSL

SSL(Secure Socket Layer,安全套接字层),位于可靠的<mark>面向连接</mark>的<mark>网络层</mark>协议和<mark>应用层</mark>协议之间的一种协议层(传输层)。
SSL通过

  • 相互认证、使用数据签名确保完整性、
  • 使用加密确保私密性,

以实现客户端和服务器之间的安全通信。
<mark>该协议由两层组成:SSL记录协议和SSL握手协议</mark>

<mark>核心概念:加密算法、数字证书、CA</mark>

SSL是netscape开发的专门用户保护Web通讯的,目前版本为3.0.最新版本的TLS1.0是IETF(工程任务组)指定的一种新的协议,他简历在SSL3.0协议规范之上,是SSL 3.0 的后续版本。
.
两者差别极小,可以理解为 SSL3.1,它是写入了 RFC(Request For Comments,互联网文件信息)的。

## TLS

TLS:(Transport Layer Security,传输层安全协议),用于两个应用程序之间提供保密性和数据完整性。

<mark>该协议由两层组成:TLS记录协议和TLS握手协议</mark>

TLS是传输层加密协议,它的前身是 SSL 协议,最早由 netscape 公司于 1995年发布,1999年通过 IETF 讨论和规范后,改名为 TLS

<mark>如果没有特殊要求,可以简单的理解为TSL和SSL都属于同一协议</mark>

## TLS、SSL加密算法

  • 加密算法严格来说属于编码学(密码编码学),编码是信息从一种形式或格式转换为另一种形式的过程。
  • 解码,是编码的逆工程。(对应密码学中的解密)
  • <mark>加密算法主要分为两类:对称加密算法和非对称加密算法</mark>

### 对称加密

<mark>在对称加密的算法中,使用的密钥只有一个,发收信双方都使用这个密钥对数据进行加密和解密</mark>,这就要求解密方事先必须知道加密密钥。

### 非对称加密算法(加密和签名)

  • <mark>非对称加密算法需要两个密钥:公开密钥(public key)和私有密钥(private key)</mark>
  • <mark>公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密</mark>
  • 服务器端发送加密锁给客户端
  • 定期更换公开密钥
  • <mark>服务端</mark> 通过 私钥1 生成并公布 公钥1 ,<mark>客户端</mark> 通过 公钥1 加密数据,把加密好的数据发给 <mark>服务端</mark>,<mark>服务端</mark> 用 私钥1 解密

.

  • 同理:<mark>客户端</mark> 用 私钥2 生成并公布 公钥2 ,<mark>服务端</mark> 通过 公钥2 加密数据,把加密好的数据发给 <mark>客户端</mark>, <mark>客户端</mark> 用 私钥2 解密

### 数字证书

  • 数字证书 是一个 <mark>经证书授权中心数字签名的</mark> 包含 <mark>公开密钥拥有者信息</mark> 的 公开密钥文件
  • 以数字证书为核心的加密技术可以对网络上传输的信息进行加密和解密、数字签名和签名验证,确保网上传递信息的机密性、完整性以及交易的不可抵赖性。

<mark>说白了,我们用非对称加密,通过公钥加密数据。但怎么证明我们的公钥是正确的公钥呢?(而不是黑客发来的公钥呢?)
我们只需要维护一个公钥中心,确保公钥中心中的公钥绝对正确。这个公钥中心就是CA,这个公钥就是证书!(当然,证书也包括注册中心信息)</mark>

我们会发现,虽然提供有https访问,但是很多的网上银行都会发给用户一个U盾,里面实际上保存的就是一个证书。

## TLS、SSL处理机制

  • 安全操作,即数据编码(加密)和解码(解密)的工作是由SSL一层来完成的,而其他的部分和HTTP协议没有多大的不同。


<mark>而我们能处理的只有最上面三层(应用层、会话层、传输层)</mark>

  • 而我们在会话层,首先会进行<mark>握手协议</mark>
    (<mark>相当于:生成密钥、证书</mark>)

    • 应用数据
    • 警告代码
    • 改变密码规格
    • 握手协议
  • 然后会进行 <mark>记录协议</mark>
    (<mark>即接收到数据,对数据加密解密的过程</mark>)

    • 数据分段
    • 数据压缩
    • 完整性检测
    • 数据认证
    • 数据加密

## 身份认证

<mark>最重要的阶段</mark>

  • 身份认证是建立每一个 TLS 连接不可或缺的部分。
  • 而身份认证的方式是:
    <mark>通过证书以数字方式签名的声明</mark>,
    <mark>它将公钥和持有相依私钥的主体(个人、设备和服务)身份绑定在一起</mark>。

通过在证书上签名,
CA可以核实:
证书上公钥相应的私钥 是否为 证书所指定的主体所拥有

说白了,<mark>就是确认公钥的出处,看看通过公钥与你通信的人,是否是是你要通信的人</mark>

### 身份认证流程(了解)

如果要实现证书签名,那么必须要进行证书的逐层签发。

## TLS 三方握手

<mark>在开始通信之前,客户端和服务器必须先建立连接和交换参数,这个过程就叫做握手(handshake)</mark>

  客户端 服务端 参数 随机数
1 <mark>发送</mark>♂ 接收 协议版本、加密方法 AAA(明文)
2 接收 <mark>发送</mark>♂ 数字证书 BBB(明文)
3 <mark>发送</mark>♂ 接收 DDD(密文)
说明:DDD为<mark>原始随机数CCC使用证书上公钥加密的结果</mark>
4 开始通信 开始通信

其中,第四步中:

  • 通信私钥EEE = function(AAA,BBB,CCC)
  • 通信公钥FFF = 加密算法(EEE)

# OpenSSL

OpenSSL中文手册之命令行详解(未完待续) https://blog.csdn.net/liao20081228/article/details/77159039

<mark>OpenSSL的核心本质在于证书可以由用户自己来生成</mark>(但是firefox承认,而chrome不承认)

  • <mark>为网络同通信提供安全及数据完整性的一种安全协议</mark>
    囊括:
    主要的密码算法、常用的密钥和证书封装管理功能以及SSL协议
    并提供了丰富的应用程序供测试或其他的目的使用

  • <mark>通过在一定范围内部署一台CA(Certificate Authority)服务器,
    可以实现局域网内部的证书认证和授权,保证数据传输的安全性</mark>
    也可以通过具体的部署实践,了解国际上大型CA机构的工作原理
    为企业级的证书管理提供知识积累。

## OpenSSL套件的组成成分

《openssl套件》 - https://www.cnblogs.com/strace/p/7093962.html

  • libcrypto:通用功能的加密库
  • libssl:用于实现TSL/SSL功能的库
  • openssl:多功能命令行工具

### 数据加密、解密过程

### CA工作流程

cas 默认在 https 下


<mark>而整个CA的处理流程也就是说整个OpenSSL的处理流程,
也就是说 OpenSSL中所有的操作模式都会按照标准的CA 结构完成,
需要生成一些列的层级证书
(所有的证书一定是逐步向下签发的)。</mark>

下面我们会在linux中完成所有操作

## OpenSSL证书生成流程

上面步骤,<mark>整个生成完成之后,还需要将证书转换为 Java 可以使用的证书格式,而后在可以在 服务器主机(如Tomcat)中进行配置。</mark>

1 根证书签发

在 Linux 系统里面已经集成了 OpenSSL 组件:
<mark>查看版本</mark>

 openssl  version


本次的开发为了方便的进行证书的下载,直接将所有的证书就生成在 ftp 指定的目录下(/srv/ftp) 为了方便保存,建立一个保存所有证书的文件夹。

<mark>创建存放证书的文件夹</mark>

mkdir -p /srv/ftp/cas

<mark>生成CA密钥对</mark> cakey.pem

(名字可自定义,但不推荐)

OpenSSL中文手册之命令行详解(未完待续) https://blog.csdn.net/liao20081228/article/details/77159039

openssl genrsa -out /srv/ftp/cas/cakey.pem 2048 RSA
  • genrsa - 生成密钥
  • RSA - RSA编码
  • -out /srv/ftp/cas/cakey.pem - 输出目录
  • 2048 - 密钥大小 bytes

<mark>生成根证书签发申请请求</mark> cacert.csr

openssl req -new -key /srv/ftp/cas/cakey.pem -out /srv/ftp/cas/cacert.csr -subj /CN=cas.com
  • req - 生成申请请求
  • -new - 新的请求
  • -sha1 - 摘要算法 sha1 用的很广泛
  • -key /srv/ftp/cas/cakey.pem - 密钥的位置
  • -out /srv/ftp/cas/cacert.csr - 输出的位置
  • -subj /CN=cas.com - 指定根证书的域名 cas.com
    <mark>在证书访问的时候必须以域名的形式出现(千万不要使用ip),这个域名应该是你自己的。</mark>

    随后,测试时候,通过修改hosts获得域名

<mark>根证书签发申请</mark> ca.cer

openssl x509 -req -days 3650 -sha1 -extensions v3_ca -signkey /srv/ftp/cas/cakey.pem -in /srv/ftp/cas/cacert.csr -out /srv/ftp/cas/ca.cer
  • x509
  • -req - 签发申请
  • -days 3650 - 证书有效时间 10 年
  • -extensions

<mark>根证书签发完成</mark>

其中:

  • ca.cer 根证书
  • cacert.csr 签发申请
  • cakey.pem 密钥对

2 服务器证书签发

为了与根证书的保存区分,<mark>建立一个目录</mark>:

mkdir -p /srv/ftp/cas/server

<mark>生成服务器私钥对</mark> server-key.pem

openssl genrsa -aes256 -out /srv/ftp/cas/server/server-key.pem 2048

服务器端生成私钥的时候需要设置一个密码,密码为 : java

  • -aes256:在输出之前用AES算法加密私钥值。

<mark>生成服务器证书签发申请</mark> : server.csr

openssl req -new -key /srv/ftp/cas/server/server-key.pem -out /srv/ftp/cas/server/server.csr -subj /CN=cas.com

生成服务器端证书的签发申请,创建的时候依然需要输入之前的密码:java

<mark>服务端证书签发</mark> : server.cer (同时生成:ca.srl 给客户端做认证用的)

openssl x509 -req -days 3650 -sha1 -extensions v3_req -CA /srv/ftp/cas/ca.cer -CAkey /srv/ftp/cas/cakey.pem -CAserial /srv/ftp/cas/server/ca.srl -CAcreateserial -in /srv/ftp/cas/server/server.csr -out /srv/ftp/cas/server/server.cer


服务端证书签发完成:

3 客户端证书签发


<mark>创建目录</mark>

mkdir -p /srv/ftp/cas/client

<mark>生成客户端私钥</mark>

openssl genrsa -aes256 -out /srv/ftp/cas/client/client-key.pem 2048

同样,密码设置为 java

<mark>生成客户端的证书申请</mark>

openssl req -new -key /srv/ftp/cas/client/client-key.pem -out /srv/ftp/cas/client/client.csr -subj /CN=cas.com

<mark>客户端证书签发</mark> client.cer

openssl x509 -req -days 365 -sha1 -CA /srv/ftp/cas/ca.cer -CAkey /srv/ftp/cas/cakey.pem -CAserial /srv/ftp/cas/server/ca.srl -in /srv/ftp/cas/client/client.csr -out /srv/ftp/cas/client/client.cer

注意,这里的有效时间是 一年
用了 ca.cer , cakey.pem 和 ca.srl

客户端证书签发完成

<mark>注意:该证书只针对于 cas.com 有效</mark>

4 生成Java证书

现在使用了 OpenSSL 生成的数字证书和私钥,

<mark>如果要想在java的环境下使用,需要将其转换为 PKCS#12 的编码格式的密钥文件才可以被java 的keytool工具所管理</mark>。

java 端的证书由于需要在 tomcat 上使用, 那么最终的证书建议在Tomcat 的目录中保存,而Tomcat的路径为 /usr/local/tomcat

  • 生成客户端证书 client.p12
openssl pkcs12 -export -clcerts -name cas-client -inkey /srv/ftp/cas/client/client-key.pem -in /srv/ftp/cas/client/client.cer -out /srv/ftp/cas/client/client.p12

三次输入密码,分别是:

  • 客户端证书操作密码
  • 定义一个 java客户端证书的操作密码(为了方便,我们都设置为 java)
  • 确认上面定义的 操作密码

.

这里的意思是说,浏览器如果有证书 client.p12 ,那么就能被这个证书的颁发者(这里是 cas 服务器)认同。
<mark>面用来进行 双向认证</mark>

  • <mark>生成服务器端证书 server.p12(主要由 Tomcat 使用)</mark>

    服务器有这个证书,说明这个服务被这个证书的颁发者(这里也是cas.cn)认同。
    <mark>那么,浏览器就可以通过 https 协议进行访问</mark>

openssl pkcs12 -export -clcerts -name cas-server -inkey /srv/ftp/cas/server/server-key.pem -in /srv/ftp/cas/server/server.cer -out /srv/ftp/cas/server/server.p12
  • 在本机系统中导入信任证书,随后在 “/usr/local/tomcat” 目录下生成 ca-trust.p12 证书文件
keytool -importcert -trustcacerts -alias cas.com -file /srv/ftp/cas/ca.cer -keystore /usr/local/tomcat/ca-trust.p12

那么,此时 JDK 就表示当前要使用的证书已经得到了认可

  • 使用 keytool 工具查看证书信息:
keytool -list -keystore /srv/ftp/cas/client/client.p12 -storetype pkcs12 -v

这里的密码,是java客户端证书的操作密码

# Tomcat 配置 HTTPS 访问

Tomcat 本身支持 https 访问的协议处理,如果想要进行 https 的访问,那么一定有与之匹配的服务器证书。

分为两种情况:

  • 单向认证
  • 双向认证

还有自认证,仅需要keytool即可生成,可以用来启动tomcat的https。但安全性不被所有浏览器认可

## 单向认证

所谓的单向认证指的是只是在服务器端提供有一个公共的证书,所有客户端连接之后都可以获得这个公钥,加密后,服务器端可以利用私钥进行解密处理。

<mark>打开 Tomcat 的配置文件</mark>

vim /usr/local/tomcat/conf/server.xml

【非必须】先把 80 端口的 连接器重定向到 443 端口(那样就不用手动转跳了)

<mark>在里面配置新 443 端口 的连接器(Connector)</mark>

注意:

  1. 因为单向认证,所有 clientAuth=false(后面双向认证才开启为true)
  2. 和图片不同,我们的密码是 java
 <Connector port="443" protocol="HTTP/1.1"
               connectionTimeout="20000"
               maxThreads="150" SSLEnabled="true"
               scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS"
               keystoreFile="/srv/ftp/cas/server/server.p12" 
               keystoreType="pkcs12" 
               keystorePass="java"/>

<mark>启动 Tomcat 服务器</mark>

/usr/local/tomcat/bin/catalina.sh start

<mark>证书配置</mark>

  • 如果现在不进行配置,你任何的浏览器都无法访问
    (配置之后,google还是不认的,所以我们要用 firefox 进行检验是否配置成功)
    .
    如果想要访问,则需要:
  1. 将 ca 的根证书配置到浏览器之中,
  2. 同时还需要 为整个的访问 添加域名(cas.com)

将 ca.cer 的根证书配置到浏览器的可信任证书上




<mark>然后修改 hosts 文件 把 ip 和 域名绑定就ok了</mark>

C:\Windows\System32\drivers\etc\hosts


清理DNS缓存: ipconfig /flushdns
查看DNS缓存:ipconfig /displaydns

<mark>浏览器重新启动后,输入:</mark> https://cas.com

## 双向认证

如果是双向认证,你必须配置客户端证书。(client.p12)

  1. 修改 Tomcat 的配置文件
    <mark>注意:clientAuth=“true”</mark>
  2. 重新启动 tomcat
    发现客户端是无法访问的

因为这时,我们还需要在客户端浏览器上配置客户端的访问证书

  1. 配置客户端的访问证书




4. 重开浏览器进行访问


# CAS

如果想要实现 单点登录,实际上并不需要用户自己去完成,单点登录只是一个设计思想,而<mark>很多的开发者 在实际的开发中,会专门配置一台 CAS 的认证服务器来实现单点登录</mark>。

## CAS(Central Authentication Service)介绍

CAS 是 Yale 大学发起的一个开源项目,旨在为 Web 应用系统提供一种可靠的单点登录方法
CAS 在 2004 年 12 月正式成为 JA-SIG 的一个项目(http://www.jasig.org

CAS 具有以下特点

  • 开源的企业级单点登录解决方案
  • CAS Server 为需要独立部署的 Web 应用;
  • CAS Client 支持非常多的客户端(指Web应用),包括Java、.Net、PHP、Perl、Ruby 等;

## 体系结构

在CAS的结构中主要分两部分,一部分是CAS Server,另一部分是CAS Client。

  • CAS Server:CAS Server 负责完成对用户的认证工作 , 需要独立部署 , CAS Server 会处理用户名 / 密码等凭证(Credentials)。

  • CAS Client:负责处理对客户端受保护资源的访问请求,需要对请求方进行身份认证时,重定向到 CAS Server 进行认证。(原则上,客户端应用不再接受任何的用户名密码等 Credentials )。

## 原理、流程

不懂看这里,非常非常详细!! - CAS单点登录(一)——初识SSO

CAS 作为服务器端,WEB容器(Tomcat)将作为客户端出现

  1. 普通的用户通过 CAS 客户端(Tomcat) 进行 WEB 的访问
  2. 而后 WEb 端会将用户的请求重定向给CAS服务器端
  3. 转跳到 CAS 服务器端之后,用户可以输入用户名和密码,进行系统登录;
  4. 如果认证通过,该请求会返回到 WEB 端,而后 WEB 端会接收一个 CAS 端生成的票根数据,并且使用此数据进行 CAS 认证检测【图中5】
  5. 票根检测通过后,会将CAS服务器端的用户名发送回 WEB 端

官方图解(建议看懂)

## CAS 服务器配置

清楚了 CAS 的流程之后,下面来进行 CAS 服务器的配置。

### 准备

首先CAS官方文档地址:https://apereo.github.io/cas/5.3.x/index.html,在后面我们可能随时会用到。

然后我们从Geting Started开始,在文档里面告诉我们部署CAS,推荐我们使用WAR Overlay method的方法,利用覆盖机制来组合CAS原始工件和本地自定义方法来达到自定义CAS的要求。

It is recommended to build and deploy CAS locally using the WAR Overlay method. 
This approach does not require the adopter to explicitly download any version of CAS, 
but rather utilizes the overlay mechanism to combine CAS original artifacts and local 
customizations to further ease future upgrades and maintenance.

官方给了两种编译方式,一种是Maven、另一种是Gradle,这里使用Maven安装部署。

具体的详情可以参考:https://apereo.github.io/cas/5.3.x/installation/Maven-Overlay-Installation.html
在开始之前,我们需要配置好电脑环境,笔者当前的环境为:

  • JDK 1.8
  • Maven 3.5.3
  • Tomcat 8.5(官方推荐Tomcat至少要8版本以上)

### 代码打包

我们需要下载打包成WAR的代码架子,地址为: https://github.com/apereo/cas-overlay-template

这里我们使用的CAS版本5.3.1,然后我们进入代码根目录下打开pom.xml文件,添加国内的maven镜像源地址,加快下载包的速度,因为CAS需要的包有点多,并且很大,如果为原来的地址,速度非常慢。

<mark>注意!这里我们使用的CAS版本5.3.1</mark>

<mark>注意!这里我们使用的CAS版本5.3.1</mark>
<mark>注意!这里我们使用的CAS版本5.3.1</mark>
<mark>注意!这里我们使用的CAS版本5.3.1</mark>
<mark>注意!这里我们使用的CAS版本5.3.1</mark>
<mark>注意!这里我们使用的CAS版本5.3.1</mark>
<mark>注意!这里我们使用的CAS版本5.3.1</mark>
<mark>注意!这里我们使用的CAS版本5.3.1</mark>
<mark>注意!这里我们使用的CAS版本5.3.1</mark>
<mark>注意!这里我们使用的CAS版本5.3.1</mark>
<mark>注意!这里我们使用的CAS版本5.3.1</mark>
<mark>注意!这里我们使用的CAS版本5.3.1</mark>(否者有个jar包 xmlsectool.2.0.0 死活下不了 ,且不能升级,因为 要同时升级 jdk,总之不用 5.3.1, 会遇到一个巨坑)

     <repositories>
        <repository>
            <id>sonatype-releases</id>
            <url>http://oss.sonatype.org/content/repositories/releases/</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
            <releases>
                <enabled>true</enabled>
            </releases>
        </repository>
        <repository>
            <id>sonatype-snapshots</id>
            <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
            <releases>
                <enabled>false</enabled>
            </releases>
        </repository>
        <repository>
            <id>shibboleth-releases</id>
            <url>https://build.shibboleth.net/nexus/content/repositories/releases</url>
        </repository>

        <!--添加国内镜像源地址-->
        <repository>
            <id>maven-ali</id>
            <url>http://maven.aliyun.com/nexus/content/groups/public//</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
                <updatePolicy>always</updatePolicy>
                <checksumPolicy>fail</checksumPolicy>
            </snapshots>
        </repository>
    </repositories>

更改 pom.xml 文件后,我们到项目的跟目录下,执行 mvn clean package 命令,接着就会去下载相应的 jar 包。

### 部署

(在进行 cas 部署之前,先关闭本机的 Tomcat)

<mark>将 cas.war 文件拷贝到 “/usr/local/tomcat/webapps”</mark> 目录中
(启动后生成 cas 目录)


访问

https://cas.com/cas

cas 默认了一个用户名:casuser
密码 Mellon

这里用的是 https 方法访问
你可以试下 http 方法访问(下图)
<mark>会有两个提示框(https访问只有一个)</mark>
意思分别是说

  • 橙色:http方式访问不安全
  • 蓝色:静态账号不合适吧~(下一步,我们连接数据库,解决掉蓝色的提示)

openssl 和 keytool 的区别

# 动态账号: cas 连接 MySQl

参考:

密文处理后面讲,<mark>这里密码用明文,只讲cas如何跟数据库连接</mark>。

## 环境准备

  1. <mark>数据库脚本下载</mark>

github /db目录下 https://github.com/LawssssCat/v-shop-server
csdn下载 https://download.csdn.net/download/LawssssCat/12242224


需要用到两台服务器、和一个客户端

No host ip 描述
1 cas.cn 192.168.64.10 Tomcat 、 CAS
2 db.cn 192.169.64.33 MqSQL
3 192.168.64.1 客户端

网关:192.168.64.2


准备好数据库,
尝试连接,我们弄一个明文密码的账号,方便后面登录

数据库准备好,我们就可以开始搞 cas 端了


## 配置:明文验证

我们知道cas-overlay-template是采用<mark>配置覆盖的策略来进行自定义</mark>的,
因此我们可以通过覆盖或者继承某些类重写某些方法实现自定义的需求。

### 启动内置tomcat

我们之前是把 cas 打包成 war ,放在我们自己的 tomcat 上运行。

但其实,cas 这个项目类似springboot,内置了一个tomcat 。

README.md 中的介绍

我们下面就继续配置,让 cas.war 能直接运行起来、1


将我们先前的cas.war解压,或者直接去Tomcat下webapps目录下面,打开WEB-INF目录下的classes里面的application.properties文件。(<mark>拷贝,下面用到</mark>)

<mark>修改文件</mark>

之前是 npm packages 直接打包,放tomcat的,

现在,先不打包,先进行一些修改
<mark>maven形式导入eclipse</mark>

我们现在要自定义,打开我们的项目,新建 src/main/resources 文件夹,同时将刚才的application.properties文件复制到该目录下。

<mark>现在我们就可以通过配置application.properties文件来实现对CAS服务器的自定义。</mark>

除了上面我们刚刚在Tomcat里面配置证书,我们还可以直接将证书配置到CAS服务信息里面,

打开application.properties文件,我们可以发现在开头有配置信息如下:

我们将信息更改如下:

#更改端口
server.port=443

#SSL配置
server.ssl.enabled=true
server.ssl.key-store=classpath:server.p12
#生成java证书时候的key
server.ssl.key-store-password=javacas
#申请服务端证书时候的key
server.ssl.key-password=javacas
server.ssl.keyAlias=cas-server

将证书放在resources包下面,每次打包就可以直接使用该证书了。

<mark>注意:server.ssl.keyAlias是生成证书填写的别名,不是随便填写的,可以通过keytool -list -keystore server.p12命令查看。</mark>

这里配置使用的是CAS自带的Tomcat,所以我们需要通过命令启动(与前面使用电脑自带Tomcat不同)。

详细看 README.md


### 动态账号密码

接着我们在配置文件的最后我们发现了CAS的认证配置,这里就是CAS默认用户名和密码配置的地方,我们现在对其进行更改。

默认的认证方式为静态文件认证,现在我们更改为JDBC认证方式,同时添加相关数据库驱动。

<!--数据库认证相关 start-->     
        <!--新增支持jdbc验证-->
        <dependency>
            <groupId>org.apereo.cas</groupId>
            <artifactId>cas-server-support-jdbc</artifactId>
            <version>${cas.version}</version>
        </dependency>

        <!--若不想找驱动可以直接写下面的依赖即可,其中包括HSQLDB、Oracle、MYSQL、PostgreSQL、MariaDB、Microsoft SQL Server-->
        <dependency>
            <groupId>org.apereo.cas</groupId>
            <artifactId>cas-server-support-jdbc-drivers</artifactId>
            <version>${cas.version}</version>
        </dependency>
<!--数据库认证相关 end--> 


笔者这里直接使用了CAS提供的综合驱动库,这里不推荐这个用法,具体使用什么数据库引入具体的相关驱动即可,因为引入综合包,同时也引入了太多不必要的包。

即去掉综合驱动库,并且添加

<!--数据库认证相关 start-->            
<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <version>5.1.46</version>
</dependency>
<!--数据库认证相关 end--> 

现在我们更改application.properties配置,同时注释静态用户配置,具体更改如下:

##
# CAS Server Context Configuration
#

# 。。。。 other configuration

##
# CAS Authentication Credentials
#
# cas.authn.accept.users=casuser::Mellon

#查询账号密码SQL,必须包含密码字段(修改)
cas.authn.jdbc.query[0].sql=select * from sp_manager where mg_name=?

#指定上面的SQL查询字段名(必须)
cas.authn.jdbc.query[0].fieldPassword=mg_pwd

#指定过期字段,1为过期,若过期不可用
cas.authn.jdbc.query[0].fieldExpired=expired

#为不可用字段段,1为不可用,需要修改密码
cas.authn.jdbc.query[0].fieldDisabled=disabled

#数据库连接(修改)
cas.authn.jdbc.query[0].url=jdbc:mysql://192.168.64.33:3306/vsdb?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false

#数据库dialect配置
cas.authn.jdbc.query[0].dialect=org.hibernate.dialect.MySQLDialect

#数据库用户名
cas.authn.jdbc.query[0].user=root

#数据库用户密码
cas.authn.jdbc.query[0].password=root

#数据库事务自动提交
cas.authn.jdbc.query[0].autocommit=false

#数据库驱动
cas.authn.jdbc.query[0].driverClass=com.mysql.jdbc.Driver

#超时配置
cas.authn.jdbc.query[0].idleTimeout=5000

#默认加密策略,通过encodingAlgorithm来指定算法,默认NONE不加密
cas.authn.jdbc.query[0].passwordEncoder.type=NONE
#cas.authn.jdbc.query[0].passwordEncoder.characterEncoding=UTF-8
#cas.authn.jdbc.query[0].passwordEncoder.encodingAlgorithm=MD5


登录成功


# 指定加密策略+账号过期,不可用检验

https://blog.csdn.net/Anumbrella/article/details/81149249

## 指定加密策略

常用单向加密算法有如:MD5、SHA、HMAC。

一般我们常用的加密算法就这几种。

在JDBC认证中我们也可以选择配置加密算法

  • 加密算法一般为上面的三种, MD5SHAHMAC
  • 加密类型为 NONE|DEFAULT|STANDARD|BCRYPT|SCRYPT|PBKDF2 这几种

我们在配置文件中选择加密类型,指定加密算法。

前面配置不变指定 JDBC配置 ,后面的配置为密码加密策略,配置如下:

##
# CAS Authentication Credentials
#
# cas.authn.accept.users=casuser::Mellon

##
# JDBC配置
#
#查询账号密码SQL,必须包含密码字段(修改)
cas.authn.jdbc.query[0].sql=select * from sp_manager where mg_name=?

#指定上面的SQL查询字段名(必须)
cas.authn.jdbc.query[0].fieldPassword=mg_pwd

#指定过期字段,1为过期,若过期不可用
cas.authn.jdbc.query[0].fieldExpired=mg_expired

#指定账号不可用字段,1为不可用,需要修改密码
cas.authn.jdbc.query[0].fieldDisabled=mg_disabled

#数据库连接(修改)
cas.authn.jdbc.query[0].url=jdbc:mysql://192.168.64.33:3306/vsdb?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false

#数据库dialect配置
cas.authn.jdbc.query[0].dialect=org.hibernate.dialect.MySQLDialect

#数据库用户名
cas.authn.jdbc.query[0].user=root

#数据库用户密码
cas.authn.jdbc.query[0].password=root

#数据库事务自动提交
cas.authn.jdbc.query[0].autocommit=false

#数据库驱动
cas.authn.jdbc.query[0].driverClass=com.mysql.jdbc.Driver

#超时配置
cas.authn.jdbc.query[0].idleTimeout=5000

#默认加密策略,通过encodingAlgorithm来指定算法,默认NONE不加密
#可选 NONE|DEFAULT|STANDARD|BCRYPT|SCRYPT|PBKDF2
cas.authn.jdbc.query[0].passwordEncoder.type=DEFAULT
#DEFAULT表示通过DefaultPasswordEncoder进行加密
#字符类型(DefaultPasswordEncoder需要)
cas.authn.jdbc.query[0].passwordEncoder.characterEncoding=UTF-8
#加密算法
cas.authn.jdbc.query[0].passwordEncoder.encodingAlgorithm=MD5
#加密盐
#cas.authn.jdbc.query[0].passwordEncoder.secret=
#加密字符长度
#cas.authn.jdbc.query[0].passwordEncoder.strength=16

同时修改我们数据库表字段,添加字段:过期(mg_expired)/账号停用(mg_disabled)


use vsdb;

-- ----------------------------
-- Table structure for sp_manager
-- ----------------------------
DROP TABLE IF EXISTS `sp_manager`;
CREATE TABLE `sp_manager` (
  `mg_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `mg_name` varchar(32) NOT NULL COMMENT '名称',
  `mg_pwd` char(32) NOT NULL COMMENT '密码',
  `mg_salt` char(36) NOT NULL COMMENT 'salt',
  `mg_time` int(10) unsigned NOT NULL COMMENT '注册时间',
  `role_id` tinyint(11) NOT NULL DEFAULT '0' COMMENT '角色id',
  `mg_mobile` varchar(32) DEFAULT NULL,
  `mg_email` varchar(64) DEFAULT NULL,
  `mg_expired` tinyint(2) default 0 null comment '0:表示启用 1:表示过期' ,
  `mg_disabled`  tinyint(2)  default 0 null comment '0:表示启用 1:表示禁用',
  PRIMARY KEY (`mg_id`)
) ENGINE=InnoDB AUTO_INCREMENT=510 DEFAULT CHARSET=utf8 COMMENT='管理员表';

-- ----------------------------
-- Records of sp_manager
-- ----------------------------
INSERT INTO `sp_manager` VALUES ('500', 'admin', '4e06b3cee0dc656695020bf34e07220f', 'd5a76533-c05d-49e5-8653-6bc1397dc6ce', '1486720211', '0', '12345678', 'adsfad@qq.com', '0','0');
INSERT INTO `sp_manager` VALUES ('502', 'linken', '123456', 'b83b2044-00b5-4525-92a2-89ce8eb2fb79 ', '1486720211', '34', '1213213123', '明文', '0','0');
INSERT INTO `sp_manager` VALUES ('505', 'bilibili', 'e10adc3949ba59abbe56e057f20f883e', 'b83b2044-00b5-4525-92a2-89ce8eb2fb79 ', '1486720211', '34', '密码123456', 'MD5加密,可用', '0','0');
INSERT INTO `sp_manager` VALUES ('501', 'alan', 'e10adc3949ba59abbe56e057f20f883e', 'b83b2044-00b5-4525-92a2-89ce8eb2fb79 ', '1486720211', '34', '密码123456', 'MD5加密,过期', '1','0');
INSERT INTO `sp_manager` VALUES ('504', 'cat', 'e10adc3949ba59abbe56e057f20f883e', 'b83b2044-00b5-4525-92a2-89ce8eb2fb79 ', '1486720211', '34', '密码123456', 'MD5加密,不可用', '0','1');
INSERT INTO `sp_manager` VALUES ('508', 'asdf1', '116e8a4f2553aa7c23b866c23f93b975','7e3c19c2-5a29-4a0f-8956-60f55bc24b58' ,  '1511853015', '30', '123123', 'adfsa@qq.com', '0','0');
INSERT INTO `sp_manager` VALUES ('509', 'asdf123', 'b81c3a9a920620d2e9e2718e963947bc', '40fb1593-4b85-4c1e-88b1-5375c172167b', '1511853353', '40', '1111', 'asdf@qq.com', '0','0');

然后我们启动应用。当我们运行起CAS,输入原来的用户名和密码

  • linken
  • 123456


<mark>并不能登录,因为我们更改密码验证为MD5加密模式了</mark>。

题外话:
linux md5 加密字符串和文件方法

  • 123456 经过 MD5 加密的结果:
    e10adc3949ba59abbe56e057f20f883e

我们换个账号

  • 账号:bilibili
  • 密码:123456

再次登录,可以发现登录成功。由此验证我们加密成功!

接着我们 用 账号:cat 密码:123456 验证 账号可用 ,登录失败,说明设置成功

接着我们 用 账号:alan 密码:123456 验证 账号过期 登录失败,说明设置成功


# 自定义加密类

自定义密码统一为 6个a

package cn.cas;

import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.StringUtils;

/** * @author lawsssscat */
public class MyPasswordEncoder implements PasswordEncoder {
    @Override
    public String encode(CharSequence charSequence) {
        String encode = charSequence.toString();
        if (StringUtils.isEmpty(encode)) {
            return null;
        }
        // charSequence为输入的用户密码
        return encode;
    }

    @Override
    public boolean matches(CharSequence charSequence, String s) {
        // 当encode方法返回不为null时,matches方法才会调用,charSequence为encode返回的字符串
        // str字符串为数据库中字段返回的值
        String encode = charSequence.toString();
        return "aaaaaa".equals(encode);
    }
}