1. 综述
OAuth 2.0是一个关于授权的开放网络标准,它定义了四种授权方式,授权码模式(authorization code)是功能最完整、流程最严密的授权模式。它的特点就是通过客户端的后台服务器,与”服务提供商”的认证服务器进行互动。
2. 角色
OAuth 定义了4种角色:
- 客户端(Client):试图访问受保护资源的
第三方应用
,它需要得到资源拥有者
的授权。 - 资源所有者(Resource Owner):授予
客户端
访问权限的实体或人。 - 资源服务器(Resource Server):托管
资源所有者
信息的服务器。 - 授权服务器(Authorization Server):是提供给
资源所有者
使用的服务器,它能批准或拒绝客户端的请求。授权服务器和资源服务器可以是同一个服务器。
3. 授权码模式
3.1 登记第三方应用
在使用 OAuth 授权之前,必须要在授权服务器处登记新的第三方应用,登记后:
- 授权服务器会设置第三方应用的
redirect_uri
,这是第三方应用接受授权码的地址; - 第三方应用程序会获得一个
client_id
和secret
。
3.2 授权过程
3.2.1 总览
sequenceDiagram
participant 第三方应用
participant 用户
participant 授权服务器
第三方应用->>授权服务器: 认证请求
授权服务器->>用户: 用户授权页面
用户->>授权服务器: 用户授权
授权服务器->>第三方应用: 重定向 URI,返回授权码
第三方应用->>授权服务器: 请求访问令牌
授权服务器->>第三方应用: 返回访问令牌
3.2.2 认证请求
用户访问第三方应用,第三方应用发出认证请求、调用授权服务器,成功后将用户重定向到授权服务器的授权页面:
GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
Host: authorization-server.com
参数:
- response_type = code:code 是固定值,代表授权类型是授权码登录;
- client_id:平台授予的
client_id
; - redirect_uri:表示授权完成后的回调地址;
- scope:一个或多个范围值,表示请求内容作用域,一般是固定值;
- state:由第三方应用生成的随机字符串,稍后第三方应用将验证该字符串。
3.2.3 用户授权
用户通过填写用户名、密码等方式授权。
3.2.4 重定向 URI
认证通过后,授权服务器调用redirect_uri
返回授权码:
HTTP/1.1 302 Found
Location: https://authorization-server.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz
参数:
- code:授权服务器返回的授权码;
- state:授权服务器返回第一步中第三方应用发送的state,第三方应用要对比 state 值。
3.2.5 请求访问令牌
第三方应用访问授权服务器请求访问令牌(Access Token):
POST /token
grant_type=authorization_code&
code=SplxlOBeZQQYbYS6WxSbIA&
redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET
Host: authorization-server.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
参数:
- grant_type=authorization_code:authorization_code是固定值,代表授权类型是授权码登录;
- code:上一步获得的授权码;
- redirect_uri:必须与原始链接中提供的重定向URI相同
- client_id:第三方应用从授权服务器获得的
client_id
; - client_secret:第三方应用从授权服务器获得的
secret
。
成功后授权服务器返回访问令牌:
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",
"scope":"scope"
}
参数:
- access_token:表示访问令牌,必选项。
- token_type:表示令牌类型,可以是bearer类型或mac类型。
- expires_in:表示过期时间,单位为秒。
- refresh_token:表示更新令牌,用来获取下一次的访问令牌,可选项。
- scope:表示权限范围,此项可省略。
3.2.6 用户登录
第三方应用接受上一步授权服务器返回的访问令牌和到期时间,执行用户登录。
4. 授权码模式的变形
以上介绍了授权码模式的实现,但是现实中通常会有一个统一登录平台,用户从统一平台登录后,就能直接访问各个子系统。这需要对授权码模式进行一些改变。
4.1 总览
sequenceDiagram
participant 用户
participant 统一登录平台
participant 授权服务器
participant 第三方应用
用户->>统一登录平台: 登录
统一登录平台->>+授权服务器: 验证用户
授权服务器->>-统一登录平台: 返回校验结果
统一登录平台->>+第三方应用: 返回授权码
第三方应用->>+授权服务器: 请求访问令牌
授权服务器->>-第三方应用: 校验并返回访问令牌
第三方应用->>-用户: 创建session, 设置cookie, 并返回302响应
4.2 代理登录
在授权码模式的基础上,省略了认证请求
过程,直接由授权服务器把授权码发送给第三方应用。因此需要第三方开放代理登录接口。
请求:
GET /sin?code=AFE206obF&callback=rescall
Content-Type:
text/javascript;charset=UTF-8
Host: third-party.com
参数:
- code:授权码。
- callback:要求最终返回给用户的
jsonp
响应函数名,使用jsonp
是为了解决跨域
问题。
之后第三方应用请求访问令牌
、授权服务器返回请求令牌
与上节完全一样。
最终给用户的响应:
HTTP/1.1 302 FOUND
Content-Type:
text/javascript;charset=UTF-8
Date:
Thu, 01 Jun 2017 07:33:46 GMT
Server:
Apache-Coyote/1.1
Set-Cookie:
JSESSIONID=F7E3801FCB894A422AD7AC17A6EDCFCF; Path=/iotmgr/; HttpOnly
Set-Cookie:
sessss=456safas; HttpOnly
Transfer-Encoding:
Chunked
Response:
rescall({"respdesc":"success","respcode":"0"})