前言
本周文章选题为 探究 RFC-6749 : OAuth2.0。
本文将会介绍
- OAuth2.0中的相关要点
- OAuth2.0的4种许可模式
OAuth2.0 相关要点
OAuth2.0的作用
(摘自维基百科)
OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。
OAuth2.0 中的角色
- 资源所有者: 就是用户本人(假设这个资源是那个用户的)
- 资源服务器: 可以获取资源的服务器
- 客户端: 为 资源所有者 发起访问资源的应用程序,就是 申请授权的应用
- 授权服务器: 用于授权的服务器....(可以与资源服务器是同一服务器)
OAuth2.0 基本流程
- 用户允许 第三方授权 (例如用户想用QQ 登录 )
- 然后用不同的模式获取到 access_token (如前言所说,有4个方法)
- 用access_token 去访问 开放的接口
- access_token如果过期了,就用refresh_token去更新token
OAuth2.0 的四种许可模式
假设端点地址:
- 客户端回调地址: client.auth.com/cb
- 授权端点地址: server.auth.com/authorize
- 令牌端点地址: server.auth.com/token
模式一: 授权码模式
个人觉得用的最多的模式,微信,QQ都是用这个模式
基本步骤
- 客户端 携带自己的参数(response_type,客户端标识、请求范围、state和重定向URI)跳转访问 授权端点
- 授权端点返回302跳转, 带着 code 和 state 跳转到 重定向端点(重定向URI)
- 重定向端点 拿着参数(grant_type,code,重定向URI) 令牌端点 发起获取token请求
- 令牌端点 返回token
详细步骤
步骤一: 客户端 跳转访问 授权端点(其实就是页面跳转而已- -)
带上参数 跳转至 授权端点
http://server.auth.com/authorize?response_type=code&client_id=asdewq&state=asd&scope=all
参数项 | 说明 | 是否必须 |
---|---|---|
response_type | 请求类型,固定值:"code" | √ |
client_id | 客户端ID,就是前面说的在注册时拿到的client_id | √ |
redirect_uri | 重定向端点,如果注册时提交了就不需要了 | × |
scope | 授权范围,自定义字符串 | × |
state | 状态值,用来进行 跨站请求伪造(CSRF)保护,随意字符串 | × |
** 此时用户应该在这里进行登陆操作!!!**
** 登陆成功后进行下面的返回 **
正常返回: code=授权码,state=之前提交的state,一模一样的返回
HTTP/1.1 302 Found
Location: https://client.auth.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=qwe
错误响应:有点复杂
HTTP/1.1 302 Found
Location: https://client.auth.com/cb?error=access_denied&state=qwe
参数项 | 说明 | 是否必须 |
---|---|---|
error | 请求类型,ASCII固定值 invalid_request:请求缺少必需的参数、包含无效的参数值、包含一个参数超过一次或其他不良格式 unauthorized_client:客户端未被授权使用此方法请求授权码。 access_denied:资源所有者或授权服务器拒绝该请求。 unsupported_response_type:授权服务器不支持使用此方法获得授权码。 invalid_scope:请求的范围无效,未知的或格式不正确。 server_error:授权服务器遇到意外情况导致其无法执行该请求。 temporarily_unavailable:授权服务器由于暂时超载或服务器维护目前无法处理请求。 |
√ |
error_description | 错误描述,详细的描述,没有也可以 | × |
error_uri | 查看错误详细的地址 | × |
state | 之前传过来的state,如果有,一定要返回 | ×/√ |
**步骤二: 跳转到 重定向端点 **
因为步骤一中,完成登陆验证之后,应该跳转到 重定向端点 .....(恩...就是这样)
**步骤三: 请求token **(有一点要注意,协议中规定token的传输,应该使用TLS来传输)
步骤二中跳转过来时,应该拿着code去兑换token,这步是由客户端的后台操作,在前端页面是不知道的
发送如下POST请求,到令牌端点:
POST /token HTTP/1.1
Host: server.auth.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
参数项 | 说明 | 是否必须 |
---|---|---|
grant_type | 授权类型,固定值:"authorization_code" | √ |
code | 刚刚获取到的code | √ |
redirect_uri | 回调地址,如果步骤一中有,那么现在也要有,而且值需要一样 | ×/√ |
client_id | 在资源服务器中注册的ID,不建议在参数中添加,应用请求头的Authorization代替 | ×/√ |
client_secret | (原文档中没提及的项,但实际应用中应该存在,所以最好使用Authorization)在资源服务器中注册的key,不建议在参数中添加,应用请求头的Authorization代替 | ×/√ |
关于Authorization,的生成方式:先得到 client_id+":"+client_secret 字符串(例如: admin_id:admin_psw),然后在进行base64,再在前面加上"Basic",然后再放入头即可 例如 Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
步骤四 : 获取token
其实是和步骤三连连续着的,一个是请求,一个是返回
成功返回:
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", //token的类型,这个有点深奥,关乎到rfc6750和其他,暂时不深入
"expires_in":3600, //access_token过期时间
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value" //其他想添加的参数,可有可无
}
失败返回:
HTTP/1.1 400 Bad Request
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"error":"invalid_request"
}
参数项 | 说明 | 是否必须 |
---|---|---|
error | 请求类型,ASCII固定值 invalid_request:请求缺少必需的参数、包含不支持的参数值(除了许可类型)、重复参数、包含多个凭据、采用超过一种客户端身份验证机制或其他不规范的格式。 invalid_client:客户端身份验证失败(例如 Authorization 验证失败) invalid_grant:提供的授权许可(如授权码、资源所有者凭据)或刷新令牌无效、过期、吊销、与在授权请求使用的重定向URI不匹配或颁发给另一个客户端。 unauthorized_client:进行身份验证的客户端没有被授权使用这种授权许可类型。 unsupported_grant_type:授权许可类型不被授权服务器支持。 invalid_scope:请求的范围无效、未知的、格式不正确或超出资源所有者许可的范围。 |
√ |
error_description | 错误描述,详细的描述,没有也可以 | × |
error_uri | 查看错误详细的地址 | × |
以上就是 授权码模式,其他模式的返回与请求,很多都是一样的,所以可能会引用上面的步骤
没错,看完 授权码模式 模式,基本就可以知道其他模式的步骤操作了,基本都差不多
模式二: 隐式授权模式
这个模式和授权模式差不多,但是中间少了code,减少了交互的次数,挺高了性能,但安全性也减低了
基本步骤
- 客户端 携带自己的参数(response_type,客户端标识、请求范围、state和重定向URI)跳转访问 授权端点
- 授权端点返回302跳转, 带着 token 跳转到 重定向端点(重定向URI)
详细步骤
** 步骤一:跳转访问 **
跟 授权码模式 的步骤一基本一样,唯一不同的地方是 response_type 的值改为 "token"
http://server.auth.com/authorize?response_type=token&client_id=asdewq&state=asd&scope=all
此时用户进行登陆后跳转
** 步骤二:授权端点返回302跳转, 带着 token 跳转到 重定向端点 **
这里的返回参数,就跟授权码模式 的步骤四中的参数一模一样,只是携带参数的方式不一样而已
授权端点的成功返回:
HTTP/1.1 302 Found
Location: http://client.auth/cb?access_token=2YotnFZFEjr1zCsicMWpAA&state=xyz&token_type=example&expires_in=3600
此时用户代理(浏览器)跳转这个页面就完成了....
模式三: 资源所有者密码凭据许可
这个协议上规定,客户端不允许记录 资源所有者账号密码的,但如果你不是服务器提供商,谁知道有没有保存?
这步
基本步骤
- 把 你在服务提供商(例如QQ)的账号密码提供给 客户端
- 客户端 用资源所有这给的账号密码(就是上步获取的账号密码)
详细步骤
步骤一:提供账号密码
这步没有要求你怎么提供,所以只要 客户端可以拿到你的账号密码就行了
步骤二:拿着账号密码去拿token
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=johndoe&password=A3ddj3w
没错,就是一个post请求就可以了
返回可以参考 授权码模式 的步骤四
模式四: 客户端凭据许可
这个是一个跟上面三个不同的模式,不需要用户的信息,那怎么知道这个用户是谁?所以这个不适合一些情况
基本步骤
- 没错,就一步,拿着cliend_id去拿token就可以了
详细步骤
步骤一:请求token
请求如下:就只有grant_type,和Authorization了
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
返回一样是参考 授权码模式 的步骤四
后语
前段时间真的忙成狗了,现在刚刚辞职了,但感觉一周一更还是挺累的(虽然我现在好像也没做到→_→)...
所以 我砍掉了实现→_→....本来还是像实现的,如果真的有小伙伴想看看实现的,就留言一下吧。不过看了以上的,就基本知道怎么实现了