OAuth2 标准与微服务的单点登录
目录
OAuth 2.0 是用于第三方服务授权的标准,现在常用于各种第三方服务的授权上面,比如,进小程序登录经常会询问获取用户信息。
推荐阮一峰的文章 OAuth 理解,其中对 OAuth 的流程已经写的很详细了。
简单整理一下 OAuth 2.0 的授权模式。
OAuth 2.0 授权模式
参与方 | 作用 |
---|---|
第三方(客户端) | 想要获取用户资源的服务器 |
资源服务器 | 拥有用户资源的服务器 |
用户 | 负责提供登录凭证和授权 |
认证服务器 | 提供授权入口、管理用户的授权凭证 |
授权码模式
-
未知用户访问第三方服务,第三方将用户导向认证服务器(登录)
用户访问第三方服务,第三方服务没有得到用户授权无法访问用户资源,于是响应一个 URI,跳转认证服务器。
第三方跳转 URI Search 字段
必选 字段 说明 必选 response_type
表示授权类型,此处的值固定为"code" 必选 client_id
表示客户端的ID,供认证服务器辨认来源 可选 redirect_uri
表示重定向URI 可选 scope
表示申请的权限范围 可选 state
表示第三方的当前状态,认证服务器会原封不动地返回这个值 -
用户在认证服务器完成登录,确认授权后拿到 code
在这里,用户与认证服务器交互,提供登入凭证,完成登录后,再确认授权。认证服务器生成 code 并写入 URI,用户收到 URI 会跳转回第三方服务。
完成授权的跳转 URI Search 字段
必选 字段 说明 必选 code
生成的授权码,交给第三方的,有效期很短且只能用一次 可选 state
第三方留下的 state 字段 -
第三方收到 code,向认证服务器请求 code 换 access_token
用户收到 code 即跳转回第三方,第三方收到 code 后,以第三方身份向认证服务请求访问令牌。认证服务器会验证第三方的 client_id 和 client_secret。
发往认证服务器的 URI Search 字段
必选 字段 说明 必选 grant_type
表示使用的授权模式,此处的值固定为"authorization_code" 必选 code
表示上一步获得的授权码 必选 redirect_uri
表示重定向URI,且必须与A步骤中的该参数值保持一致 必选 client_id
表示客户端ID 验证无误,认证服务器会返回访问令牌、更新令牌、该令牌的权限和过期时间。
认证服务器回复的令牌数据 Json*
必选 字段 说明 必选 access_token
表示访问令牌 必选 token_type
表示令牌类型,该值大小写不敏感 可选 expires_in
表示过期时间,单位为秒 可选 refresh_token
表示更新令牌,用来获取下一次的访问令牌 可选 scope
表示该令牌的权限范围
简化模式
上方是标准的验证流程,简化模式去掉了验证 code 的流程。步骤如下:
-
未知用户访问第三方服务,第三方将用户导向认证服务器(登录)
第三方响应一个 URI,跳转到认证服务器。
第三方跳转 URI Search 字段
必选 字段 说明 必选 response_type
表示授权类型,此处的值固定为"token" 必选 client_id
表示客户端的ID,供认证服务器辨认来源 可选 redirect_uri
表示重定向URI 可选 scope
表示申请的权限范围 可选 state
表示第三方的当前状态,认证服务器会原封不动地返回这个值 -
用户在认证服务器完成登录,确认授权后,直接获得 access_token
用户登入并授权后,认证服务器不再回复 code,而是直接响应访问令牌的 Json 数据。即这个 access_token 对用户是可见的,用户可以把这个 access_token 告诉客户端,这样客户端就可以用访问令牌访问用户资源了。
密码模式
用户要把登入凭证交给第三方,第三方把凭证交给认证服务器后,取得令牌。
-
未知用户访问第三方服务,第三方服务要求提供登入凭证
用户登入凭证仍然由认证服务器存储,第三方不能存储。第三方收到用户的凭证后,把凭证发给认证服务器。
第三方发往认证服务器的 URL Search
必选 字段 说明 必选 grant_type
表示授权类型,此处的值固定为"password" 必选 username
表示用户名 必选 password
表示用户密码 可选 scope
表示申请的权限范围 -
认证服务器验证用户凭证,成功后返回 access_token
认证服务器不需要验证第三方的身份,验证凭证后直接发放 access_token。
这个模式下,用户要把凭证(e.g. 用户名密码)交给第三方,第三方向认证服务器「以用户身份代为登录」,所以需要确保用户信任第三方,才采用这个模式,故这个模式不常用。
客户端模式
和密码模式类似,只是第三方「以自己身份登录」,登入后认证服务器返回access_token ,认证服务器不存储用户身份,而是存储第三方的凭证。用户登入则由第三方自己实现。
-
第三方向认证服务器请求 access_token
必选 请求位置 字段 说明 必选 URL Search grant_type
固定 “client_credentials” 必选 Header Authorization
Basic 认证格式 例子:
POST /token HTTP/1.1 Host: server.example.com Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW Content-Type: application/x-www-form-urlencoded grant_type=client_credentials
-
认证服务器验证第三方身份,成功后直接返回 access_token
这种方法也不常用,因为认证服务器维护的不是用户的登入凭证,而是维护第三方的登入凭证,而资源服务器存储的是用户的资源,和用户凭证已经没有关系,所以要另外建立解决方案处理用户的登入问题。这个模式适用于认证服务器和第三方都属于整个服务集群的情形。
OAuth2 在单点登录的应用
单点登录(SSO)即在多个服务中,用户只需要在认证服务器登入,拿到的 token 便可以在其他服务中使用,而不需要再重新登录。
微服务在 OAuth 中的应用
-
用户服务
用户的数据可以由认证微服务管理,提供用户信息管理、OAuth 授权入口、登录入口等接口。
相当于 OAuth 的 认证服务器
-
微服务网关
网关对请求作过滤处理,除白名单或定制外,访问接口请求必须持有 access_token,验证合法性则需要把 access_token 发给认证服务,获取令牌存储的信息和权限范围,但是不需要验证是否有权限,有无权限则交给业务微服务处理。
令牌验证通过后,按需求给请求注入权限范围,然后转发给对应的微服务;令牌验证不通过则直接阻挡这个请求,或者把请求导向认证服务入口(登入)。
-
业务和资源服务
业务服务的数据自行维护,但是用户数据是整个服务集群的,这里可以通过服务事件消息(Broker)来接收用户增删改消息,同时可能要处理数据不一致问题。
收到请求时,数据已经被网关处理过,所以一定有权限数据,此时可以检查令牌的权限范围(Scope),然后执行业务操作。
相当于 OAuth 的 资源服务器
-
外部微服务
外部微服务没有网关保护,收到 access_token 时,需要把 access_token 走外网请求到认证服务验证令牌合法性,这里就会用到 client_id 和 client_secret,向认证服务表明自己的身份,认证服务也要维护这份凭证,避免恶意第三方微服务获取到访问令牌。
相当于 OAuth 的 客户端(第三方)
总览上方架构,内外部微服务都可以用访问令牌来获取资源、操作业务,而用户只需要在认证服务登入,不需要每个微服务维护各自的用户数据。
而为了用户信息安全,认证服务要确保每个微服务收到的用户信息应该是用户唯一标识符或模糊的特征数据,隐藏用户隐私。
整理的疑问
OAuth2 授权码模式下除了用户输入账号密码外为什么还要客户端提供client id 和 client secret ?
用户登录是与认证服务交互。授权后,认证服务提供code给用户,用户将code发给客户端,客户端将Code发往认证服务取得token,这个过程需要验证客户端的身份,client id 和secret 通常用Basic封装。较另类的微信例子:要求填写客户端的域名以验证身份(真实性)
微服务下,网关服务收到带 JWT 令牌的请求,如何鉴定它是由身份服务签名的合法令牌?
JWT&OAuth+非对称加密:认证服务用 RSA 私钥签,然后将公钥发布给微服务集群,包括网关。网关拿到分发的公钥,可以用来验证请求中的 jwt 令牌是否合法。即是网关需要依赖认证服务。网关验证令牌合法后,处理Header(常用注入已登入的用户信息)后转发给业务服务。业务服务不再验证令牌合法,而是检查令牌内的权限是否正确。
附录
OAuth 介绍的部分摘抄自 阮一峰 OAuth 2.0 文章 理解OAuth 2.0
Should each microservice manage its own user-permissions and user-roles?