本系列文章
Spring Cloud :: Security :: Oauth2 - ⓪ OAuth2模型详述
Spring Cloud :: Security :: Oauth2 - ① 待定
...写在前面
文中很多专有名词在初次使用时我会标注一下中文,但是在后面使用过程中我还是会使用英文来表示,因为所有的标准的出处都是英文,中文的翻译并没有标准,用英文会减少歧义通俗易懂。
_/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/
背景
最近在做基于Spring Cloud的一系列架构,在认证、权限这一块准备采用OAuth2来做,Spring Cloud本身对于OAuth2的支持很不错,这一块叫做Spring Cloud Security
,默认就是使用OAuth2的模型来支持。本文把自己做架构过程中积累的技术以及插图分享出来。
概述
介绍OAuth2模型
本文主要描述OAuth2的模型以及基本运行原理,内容略略抽象,尽最大限度用图来描述,结合后续的基于Spring Cloud的代码和架构图理解会更为便捷。
正文
OAuth2
我们经常所说的OAuth2,顾名思义,就是OAuth模型的第二版。此版本允许第三方应用获取资源访问权限,并且在很多大型互联网企业中进行使用。
基础知识
Roles 角色
OAuth2定义的4个角色
- Resource Owner :资源拥有者,电脑前的你。
- Resource Server :资源服务器,托管受保护的数据的服务器。
- Client :客户端,请求访问资源服务器的应用。可以是网站,可以是javascript脚本,也可以是任何app等。
- Authorization Server :授权服务器,向Client(客户端)发放token(令牌)的服务器,token用于Client请求Resource Server。
佛系图解释一下(来源于RFC6749)https://tools.ietf.org/html/r...
+--------+ +---------------+
| |--(A)------- Authorization Grant --------->| |
| | | |
| |<-(B)----------- Access Token -------------| |
| | | |
| | | |
| | +----------+ | |
| |--(C)---- Access Token ---->| | | |
| | | | | |
| |<-(D)- Protected Resource --| Resource | | Authorization |
| Client | | Server | | Server |
| | | | | |
| | | | | |
| | | | | |
| | +----------+ | |
| | | |
| | | |
| | | |
| | | |
+--------+ +---------------+
- (A):授权
- (B):获得token
- (C):使用token访问Resource Server
- (D):获得受保护的数据
这张图中没有Resource Owner出现,我们姑且认为这个过程都是系统自动的,不需要人的参与。
Token 令牌
Token(令牌)是Authorization Server生成的一段类似于uuid的随机字符串,在Client请求的时候生成并返回。
令牌的类型
- Access Token : 访问令牌。允许第三方应用程序使用并访问用户的数据。此token由Client作为参数或者请求header发送到Resource Server,并且应具有有限的生命周期,过期时限由Authorization Server决定。
- Refresh Token : 刷新令牌。与access token一并生成,但与access token不同的是,它不会在每一个向Resource Server请求数据的时候发送给服务器。仅仅用于服务器过期时发送给服务器来更新access token。
Authorization grant types 授权类型
OAuth2定义了4种授权的类型,具体选用哪一种类型取决于不同的场景以及需求。
Authorization Code Grant 授予授权代码
何时使用
如果Client是Web服务器,那么默认应该使用这种模式,这也是OAuth2默认的方式。这种模式允许Client长期访问Token,并且刷新Token的续订,即使用Refresh Token。
例如:
- Resource Owner : 你
- Resource Server: Google服务器
- Client: Facebook网站
- Authorization Server:Google服务器
场景
- 网站希望获得你的Google个人资料的信息。
- 你将被Client(网站)重定向到Authorization Server(Google)
- 如果你授权访问,Authorization Server会在回调中向Client发送Authorization Code
- 使用Authorization Code向Authorization Server申请Access Token
- Client可以使用Access Token查询Resource Server并获取你的个人资料信息。
佛系架构图 参考(http://goo.gl/hbl1B)
题外话, http://www.websequencediagram... 真的很棒
『 Legend 』:
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ >=========> : Http POST request. ┃
┃ <~~~~~~~~~< : Response from server. ┃
┃ >---------> : Forward or redirect to. ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
『 Sequence Diagram 』:
┏━━━━━━━━━━━━━━━┓ ┏━━━━━━┓ ┏━━━━━━━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━━━━┓
┃Ressource Owner┃ ┃Client┃ ┃Authorization Server┃ ┃Resource Server ┃
┗━━━━━━━━━━━━━━━┛ ┗━━━━━━┛ ┗━━━━━━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━━━━┛
┃ ┃ ┃ ┃
┃ ┃ Authorization Code Request ┏━┓ ┃
┃ ┃ >===================================> ┃ ┃ ┃
┃ ┃ +----------------------------------+ ┃
┃ ┃ | Needs client_id,redirect_uri, | ┃
┃ | reponse_type=code[,scope,state] | ┃
┃ Login & Consent +----------------------------------+ ┃
┃ >===================================================> ┃ ┃ ┃
┃ ┃ ┃ ┃ ┃
┃ ┃ Authorization Code Reponse ┃ ┃ ┃
┃ ┃ <~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~< ┃ ┃ ┃
┃ ┃ ┃ ┃ ┃
┃ ┃ ┗━┛ ┃
┃ ┃ ┃ ┃
┃ ┃ ┏━┓ ┃
┃ ┃ Exchange Code For Access Token ┃ ┃ ┃
┃ ┃ >===================================> ┃ ┃ ┃
┃ ┃ +--------------------------------------------+ ┃
┃ ┃ | Needs client_id,client_secret,redirect_uri | ┃
┃ ┃ | grant_type=authorization_code,code | ┃
┃ ┃ +--------------------------------------------+ ┃
┃ ┃ Access Token [+ Refresh Token] ┃ ┃ ┃
┃ ┃ <~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~< ┗━┛ ┃
┃ ┃ ┃ ┃
┃ ┃ ┃ ┃
┏━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃loop┃ ┃ ┃ ┃ ┃ ┃
┣━━━━╋ ┃ ┃ ┃ ┃ ┃
┃ ┃ ┃ Call API with Access Token ┃ ┏━┓ ┃
┃ ┃ ┃ >===================================================================> ┃ ┃ ┃
┃ ┃ ┃ ┃ ┃ ┃ ┃
┃ ┃ ┃ ┃ Reponse with Data ┃ ┃ ┃
┃ ┃ ┃ <~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~< ┃ ┃ ┃
┃ ┃ ┃ ┃ ┗━┛ ┃
┃ ┃ ┃ ┃ ┃ ┃
┃ ┃ ┃ ┃ ┃ ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┃ ┃ ┃ ┃
┃ ┃ ┃ ┃
┏━━━━━━━━━━━━━━━┓ ┏━━━━━━┓ ┏━━━━━━━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━━━━┓
┃Ressource Owner┃ ┃Client┃ ┃Authorization Server┃ ┃Resource Server ┃
┗━━━━━━━━━━━━━━━┛ ┗━━━━━━┛ ┗━━━━━━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━━━━┛
Implicit Grant 隐性授权
何时使用
与Authorization Code Grant的方式不同的是,Client不是一个Web Server,而是嵌入在浏览器的脚本语言,比如javascript。
例如:
- Resource Owner: 你
- Resource Server: Google服务器
- Client: 使用Jquery或Angular js的客户端
- Authorization Server: Google服务器
场景:
- Client的js端希望获得Google的个人资料信息
- 你会被重定向到Google的Authorization Server
- 如果你授权使用自己的Google个人信息资料给Client,则Authorization Server会把Access Token异步回调给js的Client
- Client可以使用Access Token查询Resource Server并获取你的个人资料信息(通过js的异步调用)。
佛系架构图
『 Legend 』:
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ >=========> : Http POST request. ┃
┃ <~~~~~~~~~< : Response from server. ┃
┃ >---------> : Forward or redirect to. ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
『 Sequence Diagram 』:
┏━━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━━━━┓
┃Ressource Owner┃ ┃Client(Javascript App)┃ ┃Authorization Server┃ ┃Resource Server ┃
┗━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━━━━┛
┃ ┃ ┃ ┃
┃ ┃ Authorization Token Request ┏━┓ ┃
┃ ┃ >===================================> ┃ ┃ ┃
┃ ┃ +----------------------------------+ ┃
┃ ┃ | Needs client_id,redirect_uri, | ┃
┃ | reponse_type=token[,scope,state] | ┃
┃ Login & Consent +----------------------------------+ ┃
┃ >===================================================> ┃ ┃ ┃
┃ ┃ ┃ ┃ ┃
┃ ┃ Access Token ┃ ┃ ┃
┃ ┃ <~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~< ┃ ┃ ┃
┃ ┃ ┃ ┃ ┃
┃ ┃ ┗━┛ ┃
┃ ┃ ┃ ┃
┃ ┃ ┏━┓ ┃
┃ ┃ Access Token Info Request ┃ ┃ ┃
┃ ┃ >===================================> ┃ ┃ ┃
┃ ┃ ┃ ┃ ┃
┃ ┃ Access Token Info ┃ ┃ ┃
┃ ┃ <~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~< ┗━┛ ┃
┃ ┃ ┃ ┃
┃ ┃ ┃ ┃
┏━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃loop┃ ┃ ┃ ┃ ┃ ┃
┣━━━━╋ ┃ ┃ ┃ ┃ ┃
┃ ┃ ┃ Call API with Access Token ┃ ┏━┓ ┃
┃ ┃ ┃ >===================================================================> ┃ ┃ ┃
┃ ┃ ┃ ┃ ┃ ┃ ┃
┃ ┃ ┃ ┃ +-----------------------------+ ┃
┃ ┃ ┃ ┃ | Implement CORS For Cross | ┃
┃ ┃ ┃ ┃ | Domain Requests | ┃
┃ ┃ ┃ ┃ +-----------------------------+ ┃
┃ ┃ ┃ ┃ ┃ ┃ ┃
┃ ┃ ┃ ┃ Reponse with Data ┃ ┃ ┃
┃ ┃ ┃ <~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~< ┃ ┃ ┃
┃ ┃ ┃ ┃ ┗━┛ ┃
┃ ┃ ┃ ┃ ┃ ┃
┃ ┃ ┃ ┃ ┃ ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┃ ┃ ┃ ┃
┃ ┃ ┃ ┃
┏━━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━━━━┓
┃Ressource Owner┃ ┃Client(Javascript App)┃ ┃Authorization Server┃ ┃Resource Server ┃
┗━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━━━━┛
Resource Owner Password Credentials 授予资源拥有者密码凭证
何时使用
利用这种方式,你的凭证,一般来讲就是密码,会先发送给Client,然后通过Client发送给Authorization Server。通过这种方式可以看出,Client与Authorization Server之间应该有着绝对的信任,一般情况下,Client与Authorization Server是同等权限体系的,换句话说,应该是client.example.com与auth.example.com相同网站的不同resource级别的关系,由于用户的密码都是属于example.com体系下的,所以在client.example.com或者任何xxx.example.com中输入密码,去resource.example.com获取数据都是可以接受的。
例如:
- Resource Owner: 你
- Resource Server:resource.example.com服务器
- Client: new.example.com的服务器,需要调用自己网站的认证系统
- Authorization Server: auth.example.com服务器
场景:
- example公司开发了新的new.example.com的子系统
- 调用自己公司的auth.example.com认证
- 认证成功后从Authorization Server获取Access Token
- 利用Access Token去调用自己的resource.example.com的api获取相应数据
佛系架构图
『 Legend 』:
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ >=========> : Http POST request. ┃
┃ <~~~~~~~~~< : Response from server. ┃
┃ >---------> : Forward or redirect to. ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
『 Sequence Diagram 』:
┏━━━━━━━━━━━━━━━┓ ┏━━━━━━━┓ ┏━━━━━━━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━━━━┓
┃Ressource Owner┃ ┃Client ┃ ┃Authorization Server┃ ┃Resource Server ┃
┗━━━━━━━━━━━━━━━┛ ┗━━━━━━━┛ ┗━━━━━━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━━━━┛
┃ Authorization ┃ ┃ ┃
┃>================>┃ ┃ ┃
┃ with Credentials ┃ ┃ ┃
┃ ┃ Access Token Request ┏━┓ ┃
┃ ┃ >===================================> ┃ ┃ ┃
┃ ┃ +-------------------------------------+ ┃
┃ ┃ | Needs client_id,redirect_uri, | ┃
┃ | reponse_type=password[,scope,state] | ┃
┃ Login & Consent +-------------------------------------+ ┃
┃ >======================================================> ┃ ┃ ┃
┃ ┃ ┃ ┃ ┃
┃ ┃ Access Token ┃ ┃ ┃
┃ ┃ <~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~< ┃ ┃ ┃
┃ ┃ ┃ ┃ ┃
┃ ┃ ┗━┛ ┃
┃ ┃ ┃ ┃
┃ ┃ ┏━┓ ┃
┃ ┃ Access Token Info Request ┃ ┃ ┃
┃ ┃ >===================================> ┃ ┃ ┃
┃ ┃ ┃ ┃ ┃
┃ ┃ Access Token Info ┃ ┃ ┃
┃ ┃ <~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~< ┗━┛ ┃
┃ ┃ ┃ ┃
┃ ┃ ┃ ┃
┏━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃loop┃ ┃ ┃ ┃ ┃ ┃
┣━━━━╋ ┃ ┃ ┃ ┃ ┃
┃ ┃ ┃ Call API with Access Token ┃ ┏━┓ ┃
┃ ┃ ┃ >===================================================================> ┃ ┃ ┃
┃ ┃ ┃ ┃ ┃ ┃ ┃
┃ ┃ ┃ ┃ ┃ ┃ ┃
┃ ┃ ┃ ┃ Reponse with Data ┃ ┃ ┃
┃ ┃ ┃ <~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~< ┃ ┃ ┃
┃ ┃ ┃ ┃ ┗━┛ ┃
┃ ┃ ┃ ┃ ┃ ┃
┃ ┃ ┃ ┃ ┃ ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┃ ┃ ┃ ┃
┏━━━━━━━━━━━━━━━┓ ┏━━━━━━━┓ ┏━━━━━━━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━━━━┓
┃Ressource Owner┃ ┃Client ┃ ┃Authorization Server┃ ┃Resource Server ┃
┗━━━━━━━━━━━━━━━┛ ┗━━━━━━━┛ ┗━━━━━━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━━━━┛
Client Credentials Grant 授权客户凭证
何时使用
当Client自身是Resource Owner的场合,这时只需要认证client_id即可,本身不产生其他的授权认证。
例如:
- Resource Owner: 任何一家网站
- Resource Server:Google服务器
- Client: =Resource Owner
- Authorization Server: Google服务器
场景:
- 网站A保存自己的所有files在Google的云存储服务器
- 网站A需要通过Google Api进行files的操作,操作前必须在Authorization Server中认证
- 一旦认证成功,网站A获取Access Token来访问Google的Resource Server
- Authorization Server不会授权其他的权限给Resource Owner
佛系架构图
『 Legend 』:
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ >=========> : Http POST request. ┃
┃ <~~~~~~~~~< : Response from server. ┃
┃ >---------> : Forward or redirect to. ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
『 Sequence Diagram 』:
┏━━━━━━━━━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━━━━┓
┃Client(Resource Owner)┃ ┃Authorization Server┃ ┃Resource Server ┃
┗━━━━━━━━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━━━━┛
┃ ┃ ┃
┃ ┃ ┃
┃ ┃ ┃
┃ Access Token Request ┏━┓ ┃
┃>=======================================================> ┃ ┃ ┃
┃ +-----------------------------------------------+ ┃
┃ | Needs client_id,redirect_uri, | ┃
┃ | reponse_type=client_credentials[,scope,state] | ┃
┃ +-----------------------------------------------+ ┃
┃ ┃ ┃ ┃
┃ ┃ ┃ ┃
┃ ┃ ┃ ┃
┃ Access Token ┃ ┃ ┃
┃<~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~< ┃ ┃ ┃
┃ ┗━┛ ┃
┃ ┃ ┃
┃ ┃ ┃
┃ ┃ ┃
┏━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃loop┃ ┃ ┃ ┃ ┃
┣━━━━╋ ┃ ┃ ┃ ┃
┃ ┃ Call API with Access Token ┃ ┏━┓ ┃
┃ ┃ >=====================================================================================> ┃ ┃ ┃
┃ ┃ ┃ ┃ ┃ ┃
┃ ┃ ┃ ┃ ┃ ┃
┃ ┃ ┃ Reponse with Data ┃ ┃ ┃
┃ ┃ <~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~< ┃ ┃ ┃
┃ ┃ ┃ ┗━┛ ┃
┃ ┃ ┃ ┃ ┃
┃ ┃ ┃ ┃ ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┃ ┃ ┃
┏━━━━━━━━━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━━━━┓
┃Client(Resource Owner)┃ ┃Authorization Server┃ ┃Resource Server ┃
┗━━━━━━━━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━━━━┛