1. 引言
公司经历多年发展后,在内部存在多套信息系统,每套信息系统的作用各不相同,每套系统也都拥有自己独立的账号密码权限体系,这时,每个人员都需要记住不同系统的账号密码,人员入职和离职时,人事部门都需要对多个系统进行账号的分配和关停,更严重的是部分系统的管理权限不在人事部门,人员离职时系统的账号未能及时关停,存在较大的安全风险。
为此,公司计划建立一个统一的身份认证中心来统一管理账号密码,由认证中心来统一发放和回收账号,其他业务系统通过简单改造以实现与认证中心进行集成。比较了SAML2.0和OAuth2.0两种协议方案,最终选择了相对简单的OAuth2.0。
2. OAuth2.0
OAuth 2.0官方的介绍是:
OAuth 2.0 is the industry-standard protocol for authorization. OAuth 2.0 supersedes the work done on the original OAuth protocol created in 2006. OAuth 2.0 focuses on client developer simplicity while providing specific authorization flows for web applications, desktop applications, mobile phones, and living room devices. This specification and its extensions are being developed within the IETF OAuth Working Group.
OAuth 2.0是用于授权的行业标准协议。OAuth 2.0取代了在2006年创建的原始OAuth协议上所做的工作。OAuth 2.0专注于客户端开发人员的简单性,同时为Web应用程序,桌面应用程序,手机和客厅设备提供特定的授权流程。
在目前的系统中,各系统用户需要访问系统内的资源时,一般需要凭用户名和密码登录系统后才能访问,这时各系统自己存储和管理用户的用户名和密码,就会出现文章之初出现的问题(实际问题可能会有其他情况),而使用OAuth,用户的账号密码存储在身份认证中心,可以有效避免此类问题的产生。
关于OAuth2.0框架的描述可参见以下链接:
OAuth 2.0 Framework - RFC 6749
OAuth 2.0授权框架
2.1 角色
OAuth定义了四种角色:
- 资源所有者
能够许可对受保护资源的访问权限的实体。当资源所有者是个人时,它被称为最终用户。 - 资源服务器
托管受保护资源的服务器,能够接收和响应使用访问令牌对受保护资源的请求。 - 客户端
使用资源所有者的授权代表资源所有者发起对受保护资源的请求的应用程序。术语“客户端”并非特指任何特定的的实现特点(例如:应用程序是否是在服务器、台式机或其他设备上执行)。 - 授权服务器
在成功验证资源所有者且获得授权后颁发访问令牌给客户端的服务器。
授权服务器和资源服务器之间的交互超出了本规范的范围。授权服务器可以和资源服务器是同一台服务器,也可以是分离的个体。一个授权服务器可以颁发被多个资源服务器接受的访问令牌
2.2. 协议流程
图1中所示的抽象的OAuth 2.0流程描述了四种角色之间的交互,包括以下步骤:
- (A)客户端从资源所有者处请求授权。授权请求可以直接向资源所有者发起(如图所示),或者更可取的是通过授权服务器作为中介间接发起。
- (B)客户端收到授权许可,这是一个代表资源所有者的授权的凭据,使用本规范中定义的四种许可类型之一或者使用扩展许可类型表示。授权许可类型取决于客户端请求授权所使用的方法以及授权服务器支持的类型。
- (C)客户端与授权服务器进行身份认证并出示授权许可以请求访问令牌。
- (D)授权服务器验证客户端身份并验证授权许可,若有效则颁发访问令牌。
- (E)客户端从资源服务器请求受保护资源并出示访问令牌进行身份验证。
- (F)资源服务器验证访问令牌,若有效则处理该请求。
客户端从资源所有者获得授权许可(步骤(A)和(B)所示)的更好方法是使用授权服务器作为中介。
2.3 授权许可
授权许可是一个代表资源所有者授权(访问受保护资源)的凭据,客户端用它来获取访问令牌。本规范定义了四种许可类型——授权码、隐式许可、资源所有者密码凭据和客户端凭据——以及用于定义其他类型的可扩展性机制。
本次我们采用的是常用的授权码授权方式。
3. 授权码模式
参考:
What is the OAuth 2.0 Authorization Code Grant Type?
授权码许可
3.1 授权码模式流程
在图中所示的流程包括以下步骤:
- (A)客户端通过向授权端点引导资源所有者的用户代理开始流程。客户端包括它的客户端标识、请求范围、本地状态和重定向URI,一旦访问被许可(或拒绝)授权服务器将传送用户代理回到该URI。
- (B)授权服务器验证资源拥有者的身份(通过用户代理),并确定资源所有者是否授予或拒绝客户端的访问请求。
- (C)假设资源所有者许可访问,授权服务器使用之前(在请求时或客户端注册时)提供的重定向URI重定向用户代理回到客户端。重定向URI包括授权码和之前客户端提供的任何本地状态。
- (D)客户端通过包含上一步中收到的授权码从授权服务器的令牌端点请求访问令牌。当发起请求时,客户端与授权服务器进行身份验证。客户端包含用于获得授权码的重定向URI来用于验证。
- (E)授权服务器对客户端进行身份验证,验证授权代码,并确保接收的重定向URI与在步骤(C)中用于重定向(资源所有者的用户代理)到客户端的URI相匹配。如果通过,授权服务器响应返回访问令牌与可选的刷新令牌。
3.2 授权请求
客户端通过按(../AppendixB/b.md)使用“application/x-www-form-urlencoded”格式向授权端点URI的查询部分添加下列参数构造请求URI:
- response_type
必需的。值必须被设置为“code”。 - client_id
必需的。客户端标识。 - redirect_uri
可选的。回调的URL地址。 - scope
可选的。访问请求的范围。 - state
推荐的。客户度用于维护请求和回调之间的状态的不透明的值。当重定向用户代理回到客户端时,授权服务器包含此值。该参数应该用于防止跨站点请求伪造。
客户端使用HTTP重定向响应向构造的URI定向资源所有者,或者通过经由用户代理至该URI的其他可用方法。
例如,客户端使用TLS定向用户代理发起下述HTTP请求(额外的换行仅用于显示目的):
GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com
授权服务器验证该请求,确保所有需要的参数已提交且有效。如果请求是有效的,授权服务器对资源所有者进行身份验证并获得授权决定(通过询问资源所有者或通过经由其他方式确定批准)。
当确定决定后,授权服务器使用HTTP重定向响应向提供的客户端重定向URI定向用户代理,或者通过经由用户代理至该URI的其他可行方法。
3.3 授权响应
如果资源所有者许可访问请求,授权服务器颁发授权码,通过使用“application/x-www-form-urlencoded”格式向重定向URI的查询部分添加下列参数传递授权码至客户端:
- code
必需的。授权服务器生成的授权码。授权码必须在颁发后很快过期以减小泄露风险。推荐的最长的授权码生命周期是10分钟。客户端不能使用授权码超过一次。如果一个授权码被使用一次以上,授权服务器必须拒绝该请求并应该撤销(如可能)先前发出的基于该授权码的所有令牌。授权码与客户端标识和重定向URI绑定。 - state
必需的,若“state”参数在客户端授权请求中提交。从客户端接收的精确值。
例如,授权服务器通过发送以下HTTP响应重定向用户代理:
HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz
客户端必须忽略无法识别的响应参数。本规范未定义授权码字符串大小。客户端应该避免假设代码值的长度。授权服务器应记录其发放的任何值的大小。
响应错误
3.4 访问令牌请求
客户端通过使用按“application/x-www-form-urlencoded”格式在HTTP请求实体正文中发送下列UTF-8字符编码的参数向令牌端点发起请求:
- grant_type
必需的。值必须被设置为“authorization_code”。 - code
从授权服务器收到的授权码。 - redirect_uri
必需的,若“redirect_uri”参数包含在授权请求中,且他们的值必须相同。 - client_id
必需的,如果客户端没有与授权服务器进行身份认证。
如果客户端类型是机密的或客户端被颁发了客户端凭据(或选定的其他身份验证要求),客户端必须如
必需的,如果客户端没有与授权服务器进行身份验证。
例如,客户端使用TLS发起如下的HTTP请求(额外的换行符仅用于显示目的):
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
授权服务器必须:
- 要求机密客户端或任何被颁发了客户端凭据(或有其他身份验证要求)的客户端进行客户端身份验证,
- 若包括了客户端身份验证,验证客户端身份,
- 确保授权码颁发给了通过身份验证的机密客户端,或者如果客户端是公开的,确保代码颁发给了请求中的“client_id”,
- 验证授权码是有效的,并
- 确保给出了“redirect_uri”参数,若“redirect_uri”参数包含在初始授权请求中,且若包含,确保它们的值是相同的。
3.5 访问令牌响应
如果访问令牌请求是有效的且被授权,授权服务器如5.1节所述颁发访问令牌以及可选的刷新令牌。如果请求客户端身份验证失败或无效,授权服务器如5.2节所述的返回错误响应。
一个样例成功响应:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}