微服务对于用户资源访问如何控制:
用户通过授权服务来实现鉴权,把用户访问Session映射成一个Token
。所有远程访问资源服务器相关的API必须提供Token
。然后资源服务器访问授权服务来识别Token
,得知Token
属于哪个用户,并了解通过这个Token可以访问什么资源。
资源访问控制--oAuth2
任何类型的应用都提供用户登录,登录结果是一个Access Token
,所有的之后的API调用都将这个Access Token
加入HTTP请求头中,被调用服务去授权服务器验证Access Token
并获取该Token可访问的权限信息。这样一来,所有服务的访问都会请求另外的服务来完成鉴权。
权限范围和角色,客户端和用户--oAuth2
在OAuth 2
中,可以定义哪个应用(网站、移动客户端、桌面应用、其他)可以访问那些资源。这里只有一个尺寸,来自哪里的哪个用户可以访问那些数据,当然也是哪个应用或者服务可以访问哪些资源。换一种说法,权限范围就是控制那些端点对客户端可见,或者用户根据他的权限来获取相关的数据。
在一个在线商店中,前端可以看做一个客户端,可以访问商品、订单和客户信息,但后端可以关于物流和合同等,另一方面,用户可以访问一个服务但并不是全部的数据,这可以是因为用户正在使用Web应用,当他不能的时候,其他用户却可以。服务之间的访问时我们要讨论的另一个维度。可以说在OAuth 2
中,客户端-权限范围关系是线性独立于用户-权限关系。
OAuth 2 在整个流程中有四种角色:
-
资源拥有者(Resource Owner) - 这里是Tom
-
资源服务器(Resource Server) - 这里是Facebook
-
授权服务器(Authorization Server) - 这里当然还是Facebook,因为Facebook有相关数据
-
客户端(Client) - 这里是某App
Tom
试图登录Facebook
,某App
将他重定向到Facebook
的授权服务器,当Tom
登录成功,并且许可自己的Email和个人信息被某App
获取。这两个资源被定义成一个Scope(权限范围)
,一旦准许,某App
的开发者就可以申请访问权限范围中定义的这两个资源。
Tom
允许了权限请求,再次通过重定向返回某App
,重定向返回时携带了一个Access Token(访问令牌)
,接下来某App
就可以通过这个Access Token
从Facebook
直接获取相关的授权资源(也就是Email和个人信息),而无需重新做Tom
相关的鉴权。而且每当Tom
登录了某App
,都可以通过之前获得的Access Token
,直接获取相关授权资源。
+--------+ +---------------+
| |--(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 ---| |
+--------+ +---------------+
如何安全的存储Access Token--JWT
+-----------+ +-------------+
| | 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"
]
}
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|
| | | |
+-----------+ +-----------+