首先分清楚一点。
JWT是一个“认证规范”,而OAuth是一个“开放标准网络协议”,并不是同一个类型的东西。
举个例子,你在服务器上存放了一些“资源”,JWT提供了一种用于发布接入令牌(Access Token),并对发布的签名接入令牌进行验证的方法,令牌(Token)本身包含了一系列声明,服务器可以根据这些声明限制用户对资源的访问。而你可以用这个token去访问你要访问的资源,而不需要每次都进行帐号密码认证。
而OAuth提供了一套详细的授权机制,你可以通过公开的或私有的设置,授权第三方应用访问特定资源。
上面的“你”指代用户。简单来说,JWT是用来证明你有权限访问特定资源,并提供一个安全方便的方式访问资源。而OAuth是你要授权第三方访问你的资源。
OAuth 2
是如何工作的
某APP希望获得Tom在FaceBook上相关的数据
OAuth 2 在整个流程中有四种角色:
资源拥有者(Resource Owner) - 这里是Tom
资源服务器(Resource Server) - 这里是Facebook
授权服务器(Authorization Server) - 这里当然还是Facebook,因为Facebook有相关数据
客户端(Client) - 这里是某App
当Tom
试图登录Facebook
,某App
将他重定向到Facebook
的授权服务器,当Tom
登录成功,并且许可自己的Email和个人信息被某App
获取。这两个资源被定义成一个Scope(权限范围)
,一旦准许,某App
的开发者就可以申请访问权限范围中定义的这两个资源。
+--------+ +---------------+
| |--(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 ---| |
+--------+ +---------------+
Tom
允许了权限请求,再次通过重定向返回某App
,重定向返回时携带了一个Access Token(访问令牌)
,接下来某App
就可以通过这个Access Token
从Facebook
直接获取相关的授权资源(也就是Email和个人信息),而无需重新做Tom
相关的鉴权。而且每当Tom
登录了某App
,都可以通过之前获得的Access Token
,直接获取相关授权资源。
为什么是JWT
OAuth 2
并不关心去哪找Access Token
和把它存在什么地方的,生成随机字符串并保存Token
相关的数据到这些字符串中保存好。通过一个令牌端点,其他服务可能会关心这个Token
是否有效,它可以通过哪些权限。这就是用户信息URL方法,授权服务器为了获取用户信息转换为资源服务器。
当我们谈及微服务时,我们需要找一个Token
存储的方式,来保证授权服务器可以被水平扩展,尽管这是一个很复杂的任务。所有访问微服务资源的请求都在Http Header中携带Token
,被访问的服务接下来再去请求授权服务器验证Token
的有效性,目前这种方式,我们需要两次或者更多次的请求,但这是为了安全性也没什么其他办法。但扩展Token
存储会很大影响我们系统的可扩展性,这是我们引入JWT(读jot)
的原因。
+-----------+ +-------------+
| | 1-Request Authorization | |
| |------------------------------------>| |
| | grant_type&username&password | |--+
| | |Authorization| | 2-Gen
| Client | |Service | | JWT
| | 3-Response Authorization | |<-+
| |<------------------------------------| Private Key |
| | access_token / refresh_token | |
| | token_type / expire_in / jti | |
+-----------+ +-------------+
简短来说,响应一个用户请求时,将用户信息和授权范围序列化后放入一个JSON字符串,然后使用Base64进行编码,最终在授权服务器用私钥
对这个字符串进行签名,得到一个JSON Web Token
,我们可以像使用Access Token
一样的直接使用它,假设其他所有的资源服务器都将持有一个RSA公钥。当资源服务器接收到这个在Http Header中存有Token
的请求,资源服务器就可以拿到这个Token
,并验证它是否使用正确的私钥签名(是否经过授权服务器签名,也就是验签
)。验签
通过,反序列化后就拿到OAuth 2
的验证信息。
验证服务器返回的信息可以是以下内容:
access_token - 访问令牌,用于资源访问
refresh_token - 当访问令牌失效,使用这个令牌重新获取访问令牌
token_type - 令牌类型,这里是
Bearer
也就是基本HTTP认证expire_in - 过期时间
jti - JWT ID
由于Access Token
是Base64编码
,反编码后就是下面的格式,标准的JWT格式。也就是Header
、Payload
、Signature
三部分。
{
"alg":"RS256",
"typ":"JWT"
}
{
"exp": 1492873315,
"user_name": "reader",
"authorities": [
"AURH_READ"
],
"jti": "8f2d40eb-0d75-44df-a8cc-8c37320e3548",
"client_id": "web_app",
"scope": [
"FOO"
]
}
&:lƧs)ۡ-[+
F"2"Kآ8ۓٞ:u9ٴ̯ޡ 9Q32Zƌ$ec{3mxJh0DF庖[!뀭N)㥔knVVĖV|夻ׄE㍫}Ŝf9>'<蕱굤Bۋеϵov虀DӨ8C4K}Emޢ YVcaqIW&*uʝub!*Ť\՟-{ʖX܌WTq
使用JWT可以简单的传输Token
,用RSA签名
保证Token
很难被伪造。Access Token
字符串中包含用户信息和权限范围,我们所需的全部信息都有了,所以不需要维护Token
存储,资源服务器也不必要求Token
检查。
+-----------+ +-----------+
| | 1-Request Resource | |
| |----------------------------------->| |
| | Authorization: bearer Access Token | |--+
| | | Resource | | 2-Verify
| Client | | Service | | Token
| | 3-Response Resource | |<-+
| |<-----------------------------------| Public Key|
| | | |
+-----------+ +-----------+
所以,在微服务中使用OAuth 2
,不会影响到整体架构的可扩展性。淡然这里还有一些问题没有涉及,例如Access Token
过期后,使用Refresh Token
到认证服务器重新获取Access Token
等,后面会有具体的例子来展开讨论这些问题。
如果您感兴趣,后面还会有实现部分,敬请期待~
https://help.aliyun.com/document_detail/48019.html
阿里云
实现方案简介
实现方案分为两个重要的部分:
1. Authorization server(AS):认证服务器,负责生成 id_Token 并管理公钥私钥对。
这一步需要您自行实现。实现方法,请参照下文在 API 网关配置 API。
参考上图,流程简述如下:
Consumer(调用者)向API网关发送获取 id_token 认证请求,比如:通过用户名和密码(U+P)的方式。
API 网关透传该请求到 AS。
AS 向 Provider(服务提供方)发送认证用户信息请求。
Provider 响应认证结果,若失败则直接响应错误信息。
认证结果成功,AS 生成 id_token,id_token 中包含了 User 信息(可扩展,也可包含其他必要信息)。
API 网关将 AS 返回的 id_token 响应给 Consumer。
说明:AS 不用必须是单独部署的应用,完全可以集成在 Provider 中,在整个体系中担任 id_token 生产者角色,所生成的 id_token 必须符合 OIDC(1.0版本)协议中的规范。
2. Resource server(RS):资源服务器,负责校验 id_token,并解析出相应的信息。
此部分由网关来完成。因为 API 网关目前已经集成了 RS 功能,服务提供方只需要按照相应的加密规则生成 id_token 即可。
参考上图,流程简述如下:
Consumer 用带有 id_token 的参数去请求 API 网关。
API 网关会保存校验所使用的公钥,验证并解析 id_token 获取其中的 User 信息传给 Provider,若验证失败则直接返回错误信息。
Provider 处理请求并返回结果给 API 网关。
API 网关透传 Provider 响应的结果给 Consumer。
说明:RS 在整个体系中担任 id_token 消费者角色,只有 id_token 校验通过,才能将请求转发给 Provider。
http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html
客户端必须得到用户的授权(authorization grant),才能获得令牌(access token)。OAuth 2.0定义了四种授权方式。
- 授权码模式(authorization code)
- 简化模式(implicit)
- 密码模式(resource owner password credentials)
- 客户端模式(client credentials