理解 OAuth2.0

文章转载于阮一峰老师的博客:http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html

参考文章:https://learnku.com/articles/20082

 一、应用场景

       为了理解 OAuth 的适用场景,阮老师在这里举了一个例子说明,如下:

       有一个 "云冲印" 的网站,可以将用户存储在 Google 的照片,冲印出来。这里需要说明一下"云冲印"相对于 Google 是一个第三方。

那么如果要想让"云冲印"能够打印用户存储在 Google 上的照片,就必须要能让"云冲印"能读取用户存储在 Google 上的照片。

       问题来了,Google 肯定不会让一个未经用户授权的第三方去读取用户存储在 Google 上的照片,那么"云冲印"怎么获取用户的授权?

       传统的方法就是用户将自己 Google 的帐号密码告诉"云冲印",后者就可以拿着帐号密码登录 Google 去读取用户的照片了,但是这时

大家肯定会想到这很不安全,都有哪些风险呢?

       1 如果"云冲印"保存了用户的帐号密码,那这样很不安全

       2 "云冲印"有了用户的帐号密码后,就拥有了和用户一样的权限可以读取用户所有的资料,用户没办法限制"云冲印"获得授权的范围和

有效期

       3 用户只有修改密码,才能收回"云冲印"的权限,但是这样做,会使得其他所有获得用户授权的第三方应用程序失效

       4 如果其中一个第三方应用程序被破解,那么用户的帐号密码泄露

       OAuth 就是为了解决上面的问题诞生的

二、名词定义

       1 Third-party application:第三方应用程序,本文中又称"客户端(client)",即上面例子中的"云冲印"

       2 HTTP service:HTTP 服务提供商,本文中简称"服务提供商",即上面例子中的"Google"

       3 Resource Owner:资源拥有者,本文中指的是"用户"

       4 User Agent:用户代理,本文中就是浏览器

       5 Authorization server: 认证服务器,服务提供商专门用来解决认证处理的服务器

       6 Resource server:资源服务器,服务提供商存放用户所拥有资源的服务器,它与认证服务器可以是一台服务器也可以不是一台服务器

      了解了上面这些名词,可以知道,OAuth 其实就是"客户端"安全可控的获取"用户授权",与"服务提供商"交互 

三、OAuth 的思路

       OAuth 在客户端和服务提供商之间,设置了一个"授权层",客户端不能直接登录服务提供商,只能登录授权层,以此将用户和客户端区分

开来,客户端登录授权层所用的令牌(token),与用户的密码不同。用户在登录的时候可以指定授权层令牌的权限范围和有效期

       客户端登录授权层之后,服务提供商根据令牌的权限范围和有效期,向客户端开放用户存储的资料

四、运行流程

       OAuth2.0 的运行流程如下图:

    A: 用户打开客户端以后,客户端需要用户给与权限

    B:用户同意给与客户端授权

    C:客户端使用上一步获得的授权,向认证服务器申请令牌

    D:认证服务器对客户端进行认证以后,确认无误,同意发放令牌

    E:客户端使用令牌,向资源服务器申请获得资源

    F:资源服务器确认令牌无误后,同意向客户端开放资源

    上面六步中,B 是关键的一步,用户怎么才能客户端授权,客户端被授权后访问认证服务器申请令牌,然后凭借有效的令牌访问资源服务器,

下面看一下客户端获取授权的四种模式

五、客户端的授权模式

      客户端必须获得用户授权之后,才能拿到令牌(access token),OAuth2.0 提供了四种授权方式,阮一峰老师的博客里面详解每一种,在这里我

只介绍下常用的两种模式

      授权码模式(authorization code)

      简化模式(implicit)

六、授权码模式

      授权码模式是目前功能最完善,流程最严密的授权模式,它的特点就是通过客户端的后台服务器和服务提供商的认证服务器进行互动,如下图:

       A:用户访问客户端,客户端将用户导向认证服务器

       B:此时会弹出相关页面让用户选择是否同意授权给客户端

       C:假设用户同意给与授权,认证服务器将用户导向事先指定好的"重定向URI",同时附上一个授权码(authorization code)

       D:客户端收到授权码之后,附上之前的重定向URI,向认证服务器申请令牌(access token),这一步是在客户端的服务器上完成的

       E:认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送令牌(access token)和刷新令牌(refresh token)

       下面是上面这些步骤所需要的参数

       A 步骤中,客户端申请认证的URI:

       response_type:表示授权类型,必选项,此处为固定值 "code"

       client_id:表示客户端的ID,必选项

       redirect_uri:表示重定向 URI,可选项

       scope:表示申请的权限范围,可选项

       state:表示客户端当前状态,可以试任意值,认证服务器会原封不动的返回这个值

       如下示例:

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

  C 步骤中,认证服务器返回给客户端的参数:

       code:授权码,授权码的有效期比较短,并且只能使用一次

       state:如果客户端中的请求中包含这个参数,则认证服务器必须原封不动的回应这样一个参数

       如下示例:

HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
          &state=xyz

  D 步骤中,客户端向认证服务器申请令牌的HTTP请求的参数:

       grant_type:表示使用的授权模式,此处为固定值:authorization code

       code:表示上一步获取的授权码,必填

       redirect_uri:表示重定向URI,如果授权请求中包含 redirect_uri 则返回时必填

       client_id:客户端 ID

       如下示例:

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

  E 步骤认证服务器向客户端发送的请求回复参数:

       access_token:表示令牌

       token_type:表示令牌类型,该值大小写不敏感,必选项,可以是bearer类型或mac类型

       expires_in:表示过期时间,单位为秒

       refresh_token:表示更新令牌,用来获取下一次令牌

       scope:表示权限范围,如果与客户端申请的范围一致,可以省略

       如下示例:

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"
     }

七、简化模式

       简化模式(简化获取授权码流程)不通过第三方应用程序的服务器,直接在浏览器中向认证服务器申请令牌,跳过"授权码"这个流程,

所有步骤都是在浏览器中完成的,如下图所示:

      步骤如下:

      A:用户访问客户端,客户端将用户导向认证服务器

      B:用户决定是否给与客户端授权

      C:假设用户同意授权,认证服务器将用户导向客户端指定的"重定向URI",并在 URI的 HASH 部分包含了访问令牌

      D:浏览器向资源服务器发出请求,其中不包括上一步收到的 HASH 值

      E:资源服务器返回一个网页,其中包含的代码可以获取 HASH 值中的令牌

      F:浏览器执行上一步获取得脚本,提取出令牌

      G:浏览器将令牌发给客户端

      下面是上面步骤中所需要的参数:

      A 步骤客户端发出的 HTTP 请求参数:

      response_type:表示授权类型,此处的值为固定值"token"

      client_id:表示客户端的 ID

      redirect_uri:表示重定向 URI

      scope:表示授权范围

      state:表示客户端状态,可以指定任意值,认证服务器会原封不动的返回这个值

      如下示例:

GET /authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz
        &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
    Host: server.example.com

  C步骤中,认证服务器回应客户端的URI:

       access_token:表示访问令牌

       token_type:表示令牌类型

       expires_in:表示过期时间

       scope:表示权限范围

       state:如果客户端的请求中包含这个参数,则认证服务器的回应中也需要包含一个一模一样的参数

       如下示例:

 HTTP/1.1 302 Found
     Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA
               &state=xyz&token_type=example&expires_in=3600

  在上面的例子中,认证服务器用 HTTP 头信息的 Location 栏,指定浏览器重定向的网址,注意,这个网址的 HASH 部分包含了令牌,

根据上面的步骤,下一步浏览器会访问Location指定的网址,但是 HASH 部分不会被发送,然后资源服务器发送过来的代码,会提取出HASH

中的令牌

猜你喜欢

转载自www.cnblogs.com/leeyongbard/p/10539599.html