OAuth2.0 - 初入探究

前言


本周文章选题为 探究 RFC-6749 : OAuth2.0。

本文将会介绍

  • OAuth2.0中的相关要点
  • OAuth2.0的4种许可模式

OAuth2.0 相关要点


OAuth2.0的作用

(摘自维基百科)

OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。

OAuth2.0 中的角色

  • 资源所有者: 就是用户本人(假设这个资源是那个用户的)
  • 资源服务器: 可以获取资源的服务器
  • 客户端: 为 资源所有者 发起访问资源的应用程序,就是 申请授权的应用
  • 授权服务器: 用于授权的服务器....(可以与资源服务器是同一服务器)

OAuth2.0 基本流程

  1. 用户允许 第三方授权 (例如用户想用QQ 登录 )
  2. 然后用不同的模式获取到 access_token (如前言所说,有4个方法)
  3. 用access_token 去访问 开放的接口
  4. access_token如果过期了,就用refresh_token去更新token

OAuth2.0 的四种许可模式

假设端点地址:

  • 客户端回调地址: client.auth.com/cb
  • 授权端点地址: server.auth.com/authorize
  • 令牌端点地址: server.auth.com/token

模式一: 授权码模式


个人觉得用的最多的模式,微信,QQ都是用这个模式

基本步骤
  1. 客户端 携带自己的参数(response_type,客户端标识、请求范围、state和重定向URI)跳转访问 授权端点
  2. 授权端点返回302跳转, 带着 code 和 state 跳转到 重定向端点(重定向URI)
  3. 重定向端点 拿着参数(grant_type,code,重定向URI) 令牌端点 发起获取token请求
  4. 令牌端点 返回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,减少了交互的次数,挺高了性能,但安全性也减低了

基本步骤
  1. 客户端 携带自己的参数(response_type,客户端标识、请求范围、state和重定向URI)跳转访问 授权端点
  2. 授权端点返回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

此时用户代理(浏览器)跳转这个页面就完成了....

模式三: 资源所有者密码凭据许可


这个协议上规定,客户端不允许记录 资源所有者账号密码的,但如果你不是服务器提供商,谁知道有没有保存?
这步

基本步骤
  1. 把 你在服务提供商(例如QQ)的账号密码提供给 客户端
  2. 客户端 用资源所有这给的账号密码(就是上步获取的账号密码)
详细步骤

步骤一:提供账号密码
这步没有要求你怎么提供,所以只要 客户端可以拿到你的账号密码就行了

步骤二:拿着账号密码去拿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请求就可以了
返回可以参考 授权码模式 的步骤四

模式四: 客户端凭据许可


这个是一个跟上面三个不同的模式,不需要用户的信息,那怎么知道这个用户是谁?所以这个不适合一些情况

基本步骤
  1. 没错,就一步,拿着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

返回一样是参考 授权码模式 的步骤四

后语

前段时间真的忙成狗了,现在刚刚辞职了,但感觉一周一更还是挺累的(虽然我现在好像也没做到→_→)...
所以 我砍掉了实现→_→....本来还是像实现的,如果真的有小伙伴想看看实现的,就留言一下吧。不过看了以上的,就基本知道怎么实现了

你可能感兴趣的:(OAuth2.0 - 初入探究)