Spring security Oauth2+JWT

企业级认证授权技术

一丶用户认证与授权

每个项目最基本的也是最重要的是安全,用户认证与授权,是最重要的,用户认证身份。

1.1什么是用户身份认证?

用户身份认证即用户去访问系统资源时系统要求验证用户的身份信息,身份合法方可继续访问。常见的用户身份认证表现形式有:用户名密码登录,指纹打卡等方式。

1.2什么是用户授权?

用户认证通过后去访问系统的资源,系统会判断用户是否拥有访问资源的权限,只允许访问有权限的系统资源,没有权限的资源将无法访问,这个过程叫用户授权。

二丶SSO单点登录

单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。
SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。 下图是SSO的示意图,用户登录一次即可访问多个系统

2.1丶 第三方认证需求

作为互联网项目难免需要访问外部系统的资源,同样本系统也要访问第三方系统的资源接口,一个场景下:
一个微信用户没有在本网站注册,系统可以通过请求微信系统来验证该用户的身份,验证通过后该用户便可在 本系统操作,它的基本流程如下:
Spring security Oauth2+JWT_第1张图片

从上图可以看出,微信不属于系统,系统并没有存储微信用户的账号、密码等信息,本系统如果要获取该用户的基本信息则需要首先通过微信的认证系统(微信认证)进行认证,微信认证通过后本系统便可获取该微信用户的基本信息,从而在本系统将该微信用户的头像、昵称等信息显示出来,该用户便不用在本系统注册却可以直接进行操作。

2.2什么是第三方认证(跨平台认证)?

当需要访问第三方系统的资源时需要首先通过第三方系统的认证(例如:微信认证),由第三方系统对用户认证通过,并授权资源的访问权限。

2.3丶用户认证技术方案
2.3.1 单点登录技术方案
分布式系统要实现单点登录,通常将认证系统独立抽取出来,并且将用户身份信息存储在单独的存储介质,比如:MySQL、Redis,考虑性能要求,通常存储在Redis中,如下图:
Spring security Oauth2+JWT_第2张图片

2.3.2单点登录的特点是:

1、认证系统为独立的系统。
2、各子系统通过Http或其它协议与认证系统通信,完成用户认证。
3、用户身份信息存储在Redis集群。

2.3.3 Java中有很多用户认证的框架都可以实现单点登录:

1、Apache Shiro.
2、CAS
3、Spring security CAS

2.4 Oauth2认证

第三方认证技术方案最主要是解决认证协议的通用标准 问题,因为要实现
跨系统认证,各系统之间要遵循一定的接口协议。OAUTH协议为用户资源的授权提供了一个安全的、开放而又简易的标准。同时,任何第三方都可以使用OAUTH认证服务,任何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP、JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间,因而OAUTH是简易的。互联网很多服务如Open
API,很多大公司如Google,Yahoo,Microsoft等都提供了OAUTH认证服务,这些都足以说明OAUTH标准逐渐成为开放资源授权的标准。
Oauth协议目前发展到2.0版本,1.0版本过于复杂,2.0版本已得到广泛应用。

参考:https://baike.baidu.com/item/oAuth/7153134?fr=aladdin
Oauth协议:https://tools.ietf.org/html/rfc6749

+--------+                               +---------------+
 |        |--(A)- Authorization Request ->|   Resource    |
 |        |                               |     Owner     |
 |        |<-(B)-- Authorization Grant ---|               |
 |        |                               +---------------+
 |        |
 |        |                               +---------------+
 |        |--(C)-- Authorization Grant -->| Authorization |
 | Client |                               |     Server    |
 |        |<-(D)----- Access Token -------|               |
 |        |                               +---------------+
 |        |
 |        |                               +---------------+
 |        |--(E)----- Access Token ------>|    Resource   |
 |        |                               |     Server    |
 |        |<-(F)--- Protected Resource ---|               |
 +--------+                               +---------------+

2.4.1 Oauth2包括以下角色:
1、客户端

本身不存储资源,需要通过资源拥有者的授权去请求资源服务器的资源,比如: Android客户端、Web客户端(浏览器端)、微信客户端等。

2、资源拥有者

通常为用户,也可以是应用程序,即该资源的拥有者。

3、授权服务器(也称认证服务器)

用来对资源拥有的身份进行认证、对访问资源进行授权。客户端要想访问资源需要通过认证服务器由资源拥有者授权后方可访问。

4、资源服务器

存储资源的服务器,比如,用户管理服务器存储了用户信息,服务器存储了用户信息,微信的资源服务存储了微信的用户信息等。客户端最终访问资源服务器获取资源信息。
根据分为步骤 客户端资源服务器访问授权服务器资源服务器 当客户端访问资源服务器需要认证如果认证通过则可以访问该服务器

Oauth2是一个标准的开放的授权协议,应用程序可以根据自己的要求去使用Oauth2,Oauth2实现如下目标:

1、项目访问第三方系统的资源
2、外部系统访问项目的资源
3、项目前端(客户端) 访问项目微服务的资源。
4、项目微服务之间访问资源,例如:微服务A访问微服务B的资源,B访问A的资源。

三丶Spring security Oauth2认证解决方案

采用 Spring security + Oauth2完成用户认证及用户授权,Spring security
是一个强大的和高度可定制的身份验证和访问控制框架,Spring security 框架集成了Oauth2协议,下图是项目认证架构图:

Spring security Oauth2+JWT_第3张图片

1、用户请求认证服务完成认证。
2、认证服务下发用户身份令牌,拥有身份令牌表示身份合法。
3、用户携带令牌请求资源服务,请求资源服务必先经过网关。
4、网关校验用户身份令牌的合法,不合法表示用户没有登录,如果合法则放行继续访问。
5、资源服务获取令牌,根据令牌完成授权。
6、资源服务完成授权则响应资源信息。

3.1 Spring Security Oauth2研究
项目认证服务基于Spring Security Oauth2进行构建,并在其基础上作了一些扩展,采用JWT令牌机制,并自定义了用户身份信息的内容。 本教程的主要目标是学习在项目中集成Spring Security Oauth2的方法和流程,通过Spring Security Oauth2的研究需要达到以下目标:

1、理解Oauth2的授权码认证流程及密码认证的流程。
2、理解spring Security Oauth2的工作流程。
3、掌握资源服务集成spring Security框架完成Oauth2认证的流程。

3.2搭建认证服务器

该工程是基于Spring Security Oauth2的一个二次封装的工 程,导入此工程研究Oauth2认证流程。 由于代码过多请访问:

Github:
3.3 Oauth2授权码模式
Oauth2有以下授权模式:

授权码模式(Authorization Code)
隐式授权模式(Implicit)
密码模式(Resource Owner Password Credentials)
客户端模式(Client Credentials)

其中授权码模式和密码模式应用较多,介绍授权码模式与密码模式
3.3.1授权码授权流程
上边例举网站使用微信认证的过程就是授权码模式,流程如下:

1.客户端请求第三方授权
2.用户(资源拥有者)同意给客户端授权
3.客户端获取到授权码,请求认证服务器申请 令牌
4.认证服务器向客户端响应令牌
5.客户端请求资源服务器的资源,资源服务校验令牌合法性,完成授权
6.资源服务器返回受保护资源
3.3.2申请授权码

请求认证服务获取授权码: Get请求: localhost:40400/auth/oauth/authorize?
client_id=XcWebApp&response_type=code&scop=app&redirect_uri=http://localhost

参数列表如下:
client_id:客户端id,和授权配置类中设置的客户端id一致。
response_type:授权码模式固定为code
scop:客户端范围,和授权配置类中设置的scop一致。
redirect_uri:跳转uri,当授权码申请成功后会跳转到此地址,并在后边带上code参数(授权码)。

首先跳转到登录页面:

输入账号和密码,点击Login。 Spring
Security接收到请求会调用UserDetailsService接口的loadUserByUsername方法查询用户正确的密码。当前导入的基础工程中将正确的密码硬编码为“123”,所以这里账号随意输入,密码输入123即可认证通过。
注意 密码静态的已经注释了 接下来进入授权页面:
OAuth Approval
Do you authorize ‘XcWebApp’ to access your protected resources?
首先跳转到登录页面:
Spring security Oauth2+JWT_第4张图片

输入账号和密码,点击Login。
Spring Security接收到请求会调用UserDetailsService接口的loadUserByUsername方法查询用户正确的密码。
当前导入的基础工程中将正确的密码硬编码为“123”,所以这里账号随意输入,密码输入123即可认证通过。
接下来进入授权页面:
Spring security Oauth2+JWT_第5张图片

点击“同意”。
接下来返回授权码:
认证服务携带授权码跳转redirect_uri

3.3.3申请令牌
拿到授权码后,申请令牌。
Post请求:

http://localhost:40400/auth/oauth/token

参数如下:

grant_type:授权类型,填写authorization_code,表示授权码模式
code:授权码,就是刚刚获取的授权码,注意:授权码只使用一次就无效了,需要重新申请。
redirect_uri:申请授权码时的跳转url,一定和申请授权码时用的redirect_uri一致。 此链接需要使用 http
*加粗样式
Basic认证。 什么是http Basic认证?
http协议定义的一种认证方式,将客户端id和客户端密码按照“客户端ID:客户端密码”的格式拼接,并用base64编

码,放在header中请求服务端,一个例子: Authorization:Basic WGNXZWJBcHA6WGNXZWJBcHA=
WGNXZWJBcHA6WGNXZWJBcHA= 是用户名:密码的base64编码。 认证失败服务端返回 401 Unauthorized
以上测试使用postman完成: http basic认证:

客户端Id和客户端密码会匹配数据库oauth_client_details表中的客户端id及客户端密码。
Post请求参数:
Spring security Oauth2+JWT_第6张图片

点击发送:
申请令牌成功
Spring security Oauth2+JWT_第7张图片

access_token:访问令牌,携带此令牌访问资源 token_type:有MAC Token与Bearer
Token两种类型,两种的校验算法不同,RFC 6750建议Oauth2采用 Bearer
Token(http://www.rfcreader.com/#rfc6750)。
refresh_token:刷新令牌,使用此令牌可以延长访问令牌的过期时间。
expires_in:过期时间,单位为秒。
scope:范围,与定义的客户端范围一致。

3.3.4资源服务授权
资源服务授权流程
资源服务拥有要访问的受保护资源,客户端携带令牌访问资源服务,如果令牌合法则可成功访问资源服务中的资 源,如下图:
Spring security Oauth2+JWT_第8张图片

上图的业务流程如下:

1、客户端请求认证服务申请令牌
2、认证服务生成令牌 认证服务采用非对称加密算法,使用私钥生成令牌。
3、客户端携带令牌访问资源服务 客户端在Http header 中添加: Authorization:Bearer 令牌。
4、资源服务请求认证服务校验令牌的有效性 资源服务接收到令牌,使用公钥校验令牌的合法性。
5、令牌有效,资源服务向客户端响应资源信息

3.3.4.1资源源服务授权配置
基本上所有微服务都是资源服务,这里我们在商品管理服务上配置授权控制,当配置了授权控制后如要访问商品信息则必须提供令牌。
1、配置公钥
认证服务生成令牌采用非对称加密算法,认证服务采用私钥加密生成令牌,对外向资源服务提供公钥,资源服务使用公钥 来校验令牌的合法性。将公钥拷贝到 publickey.txt文件中,将此文件拷贝到资源服务工程的classpath下
**Spring security Oauth2+JWT_第9张图片
**

3.4 Oauth2密码模式授权
密码模式(Resource Owner Password Credentials)与授权码模式的区别是申请令牌不再使用授权码,而是直接 通过用户名和密码即可申请令牌。
测试如下:
Post请求:
http://localhost:40400/auth/oauth/token
参数:
grant_type:密码模式授权填写password
username:账号
password:密码
并且此链接需要使用 http Basic认证。
Spring security Oauth2+JWT_第10张图片

上边参数使用x-www-form-urlencoded方式传输,使用postman测试如下:
Spring security Oauth2+JWT_第11张图片

注意:当令牌没有过期时同一个用户再次申请令牌则不再颁发新令牌。
3.4.1校验令牌

Spring Security Oauth2提供校验令牌的端点,如下: Get:
http://localhost:40400/auth/oauth/check_token?token=

参数:
token:令牌
使用postman测试如下:
Spring security Oauth2+JWT_第12张图片

exp:过期时间,long类型,距离1970年的秒数(new Date().getTime()可得到当前时间距离1970年的毫秒数)。
user_name: 用户名
client_id:客户端Id,在oauth_client_details中配置
scope:客户端范围,在oauth_client_details表中配置
jti:与令牌对应的唯一标识
companyId、userpic、name、utype、id:这些字段是本认证服务在Spring Security基础上扩展的用户身份信息
3.4.2刷新令牌
刷新令牌是当令牌快过期时重新生成一个令牌,它于授权码授权和密码授权生成令牌不同,刷新令牌不需要授权码
也不需要账号和密码,只需要一个刷新令牌、客户端id和客户端密码。
测试如下:
Post:http://localhost:40400/auth/oauth/token
参数:
grant_type: 固定为 refresh_token
refresh_token:刷新令牌(注意不是access_token,而是refresh_token)
Spring security Oauth2+JWT_第13张图片

刷新令牌成功,会重新生成新的访问令牌和刷新令牌,令牌的有效期也比旧令牌长。
刷新令牌通常是在令牌快过期时进行刷新。
四丶 JWT研究
4.1 JWT介绍
在介绍JWT之前先看一下传统校验令牌的方法,如下图:
Spring security Oauth2+JWT_第14张图片

问题:
传统授权方法的问题是用户每次请求资源服务,资源服务都需要携带令牌访问认证服务去校验令牌的合法性,并根 据令牌获取用户的相关信息,性能低下。
解决:
使用JWT的思路是,用户认证通过会得到一个JWT令牌,JWT令牌中已经包括了用户相关的信息,客户端只需要携带 JWT访问资源服务,资源服务根据事先约定的算法自行完成令牌校验,无需每次都请求认证服务完成授权。
JWT令牌授权过程如下图:
Spring security Oauth2+JWT_第15张图片

什么是JWT?
JSON Web Token(JWT)是一个开放的行业标准(RFC 7519),它定义了一种简介的、自包含的协议格式,用于 在通信双方传递json对象,传递的信息经过数字签名可以被验证和信任。JWT可以使用HMAC算法或使用RSA的公 钥/私钥对来签名,防止被篡改。
官网:https://jwt.io/
标准:https://tools.ietf.org/html/rfc7519
JWT令牌的优点:

1、jwt基于json,非常方便解析。
2、可以在令牌中自定义丰富的内容,易扩展。
3、通过非对称加密算法及数字签名技术,JWT防止篡改,安全性高。
4、资源服务使用JWT可不依赖认证服务即可完成授权。

缺点:

1、JWT令牌较长,占存储空间比较大。

4.2 令牌结构

通过学习JWT令牌结构为自定义jwt令牌打好基础。
JWT令牌由三部分组成,每部分中间使用点(.)分隔,比如:xxxxx.yyyyy.zzzzz Header
头部包括令牌的类型(即JWT)及使用的哈希算法(如HMAC SHA256或RSA) 一个例子如下: 下边是Header部分的内容

{ 
"alg": "HS256", 
"typ": "JWT" 
}

将上边的内容使用Base64Url编码,得到一个字符串就是JWT令牌的第一部分。 Payload
第二部分是负载,内容也是一个json对象,它是存放有效信息的地方,它可以存放jwt提供的现成字段,比 如:iss(签发者),exp(过期时间戳), sub(面向的用户)等,也可自定义字段。
此部分不建议存放敏感信息,因为此部分可以解码还原原始内容。
最后将第二部分负载使用Base64Url编码,得到一个字符串就是JWT令牌的第二部分。 一个例子:

{ 
"sub": "1234567890", 
"name": "456", 
"admin": true 
}

Signature
第三部分是签名,此部分用于防止jwt内容被篡改。
这个部分使用base64url将前两部分进行编码,编码后使用点(.)连接组成字符串,最后使用header中声明
签名算法进行签名。
一个例子

HMACSHA256( 
base64UrlEncode(header) + "." + 
base64UrlEncode(payload), secret)
base64UrlEncode(header):jwt令牌的第一部分。 
base64UrlEncode(payload):jwt令牌的第二部分。 
secret:签名所使用的密钥。 

4.3 JWT入门
Spring Security 提供对JWT的支持,本节我们使用Spring Security 提供的JwtHelper来创建JWT令牌,校验JWT令牌
等操作。
3.6.3.1 生成私钥和公钥
JWT令牌生成采用非对称加密算法
1、生成密钥证书
下边命令生成密钥证书,采用RSA 算法每个证书包含公钥和私钥

keytool -genkeypair -alias xckey -keyalg RSA -keypass xuecheng -keystore xc.keystore -storepass 
xuechengkeystore 
Keytool 是一个java提供的证书管理工具 
-alias:密钥的别名 
-keyalg:使用的hash算法 
-keypass:密钥的访问密码 
-keystore:密钥库文件名,xc.keystore保存了生成的证书 
-storepass:密钥库的访问密码 
查询证书信息: 
keytool -list -keystore xc.keystore 
删除别名 
keytool -delete -alias xckey -keystore xc.keystore 

2、导出公钥
openssl是一个加解密工具包,这里使用openssl来导出公钥信息。
安装 openssl:http://slproweb.com/products/Win32OpenSSL.html
安装资料目录下的Win64OpenSSL-1_1_0g.exe
配置openssl的path环境变量,本教程配置在

D:\OpenSSL-Win64\bin 

cmd进入xc.keystore文件所在目录执行如下命令:

keytool ‐list ‐rfc ‐‐keystore xc.keystore | openssl x509 ‐inform pem ‐pubkey

用户登录的流程图如下:
Spring security Oauth2+JWT_第16张图片

执行流程:
1、用户登录,请求认证服务
2、认证服务认证通过,生成jwt令牌,将jwt令牌及相关信息写入Redis,并且将身份令牌写入cookie
3、用户访问资源页面,带着cookie到网关
4、网关从cookie获取token,并查询Redis校验token,如果token不存在则拒绝访问,否则放行
5、用户退出,请求认证服务,清除redis中的token,并且删除cookie中的token
使用redis存储用户的身份令牌有以下作用:
1、实现用户退出注销功能,服务端清除令牌后,即使客户端请求携带token也是无效的。
2、由于jwt令牌过长,不宜存储在cookie中,所以将jwt令牌存储在redis,由客户端请求服务端获取并在客户端存储。

你可能感兴趣的:(java,java)