• 理解OAuth 2.0授权


    一、什么是OAuth 

    二、什么场景下会用到OAuth授权

    三、OAuth 2.0中的4个成员

    四、OAuth 2.0授权流程

    五、OAuth 2.0授权模式

    1、    authorization code(授权码模式)

    2、    implicit(简化模式)

    3、    resource owner password credentials(密码模式)

    4、    client credentials(客户端模式)

    六、小结

    一、什么是OAuth

      所谓的OAuth(Open Authorization)本质上就是一张开放的协议,OAuth协议为用户资源的授权提供了一个安全的、开放而又简易的标准。 与以往的授权方式不同该授权不会使第三方触及到用户的账户信息,即第三方无需使用用户名密码就可以申请该用户资源的授权,因此OAuth是安全的。这是来自百度百科对OAuth的解释。

      而OAuth2.0呢,故名思义就是OAuth的下一个版本,同时它也是授权领域的行业标准协议,OAuth2.0不支持向后兼容,即不支持OAuth1.0,彻底废止了OAuth1.0协议,OAuth2.0致力于使客户端开发者通过更简单的流程为Web应用、桌面应用以及手机客户端等设备进行授权。2012年10月,OAuth2.0协议正式发布为RFC6749。目前各大开放平台,如腾讯、新浪、百度等等也都是以OAuth2.0协议作为支撑。

    二、什么场景下会用到OAuth授权

         目前我们大多数的应用场景,也是我们最熟悉的使用环境就是使用第三方登录,如:微博,QQ,微信,豆瓣等社交平台登录,互联网发展到今天,我们也都习惯了这种登录方式,最大的好处就是便捷,简化了我们一系列的注册流程,还有一大堆帐号密码记不住的困扰,当你碰到一个不支持第三方登录的网站或者应用的时候,第一感觉就是厌恶,一顿喷。人永远离不开社交,所以通过社交平台去登录其他的平台,无疑是最受大家欢迎的方式了。  

      就拿CSDN为例,CSDN是支持第三方平台登录的,截图如下:

    若用户想使用QQ登录,那么在传统的认证模式中,客户端(CSDN)请求访问服务器上受限的资源(QQ),需要通过资源所有者(用户的QQ账户)的凭证在服务器上进行认证。为了支持第三方应用程序(对于QQ来说,CSDN是第三方应用程序,是CSDN去请求访问QQ的资源)访问受限资源,资源所有者需要向第三方应用共享其凭证(如用户QQ的帐号和密码)。那这样就会造成以下几个问题:

    • 第三方应用(CSDN)为了以后继续使用,那么会存储资源所有者的凭证,如密码;
    • 服务端需要支持密码认证,尽管密码认证不安全;
    • 第三方应用若想访问资源所有者的其他资源,资源所有者无法对其进行限制;
    • 资源所有者无法收回第三方的访问权限,除非用户主动修改密码;
    • 如果此时第三方的数据泄漏,那也会导致资源所有者其他数据的泄漏,造成重大损失。

      若此时,CSDN知道了用户的QQ密码,那CSDN可以任意去访问该用户的所有信息,而QQ无法去限制它的访问,这不管是对QQ还是用户本身都会是一件可怕的事,作为使用者,你永远都无法知道应用都干了些什么。由此OAuth2.0的出现,就是为了解决这样的问题。

    三、OAuth 2.0中的4个成员

    在OAuth2.0中有4个成员,Resource Owner、Resource Server、Client、Authorization Server,如图所示:

    在上面4个成员中,授权服务器可能与资源服务器在同一台服务器。

    四、OAuth 2.0授权流程

        流程如下,图片来自RFC6749:

    流程解析:

    1. 用户打开客户端,客户端要求向资源所有者(即用户)给予授权;
    2. 用户同意授权;
    3. 客户端得知用户同意授权后,向授权服务器获取授权;
    4. 授权服务器给予客户端授权,并将授权码(Access Token);
    5. 客户端携带授权码去请求资源服务器;
    6. 资源服务器将受限的资源开放给客户端。

    五、OAuth 2.0授权模式

        授权许可是表示客户用来获取访问令牌的资源所有者授权的凭证。此规范协议规定了4种授权类型:

    • authorization code(授权码模式)
    • implicit(简化模式)
    • resource owner password credentials(密码模式)
    • client credentials(客户端模式)

    下面详细说明各种授权模式的具体流程:

      1、authorization code(授权码模式)

    授权代码授权类型用于获取访问令牌和刷新令牌,并针对机密客户端进行优化。它是一个基于重定向的流程,因此客户端必须能够与资源所有者的用户代理(通常是Web浏览器)并且能够从授权服务器接收传入请求(通过重定向)。授权码模式是功能最完整、流程最严密的授权模式,它的特点就是通过客户端的后台服务器,与"服务提供商"的授权服务器进行互动。授权流程如下:

    流程解析:

    1. 客户端通过用户代理,重定向请求授权服务器,所需参数:客户端标识及重定向URL;
    2. 用户选择是否给予客户端授权;
    3. 授权服务器给予客户端一个认证授权码,并跳转到指定的URI;
    4. 客户端使用该授权码,重定向到授权服务器,获取令牌;
    5. 授权服务器校验该授权码以及重定向的URI后,向客户端发送令牌或者更新令牌。

    以上均个人解释,简化了RFC6749官方文档说明,大致意思是一样的。注意的一点是,在用户同意授权后,授权服务器并未直接将令牌发送给客户端,而是先向客户端发送了一个授权码,authorization code,然后再携带该授权码,再一次请求授权服务器,校验无误后,再发送令牌(access token),这一步是在后台自动完成的,这样也使OAuth授权更加安全。

        在该授权流程中,我们所需的几个参数,官方文档中要求指定的参数如下:

    • response_type 必选项 表示的是要求指定的授权类型,此处必须设置为:code
    • client_id 必选项 客户端的唯一标识
    • redirect_uri 可选项 重定向的URI
    • scope 可选项 授权的管道
    • state 建议项 表示客户端状态,授权服务器会将该状态原值返回

    看完该流程以及所需的参数后,我们结合实际情况,还是上面提到的例子,以CSDN使用QQ登录为例,看一下该过程:

    (A步骤)点击QQ登录,跳转到QQ帐号安全登录界面,即腾讯的互联平台,我们可以直接拿到此时CSDN要请求的地址:

    https://graph.qq.com/oauth2.0/show?which=Login&display=pc&

    response_type=code&

    client_id=100270989&

    redirect_uri=https://passport.csdn.net/account/login?oauth_provider=QQProvider&

    state=test

    这样我们可以很清楚的看到在上面的URL中,发起了一个get请求,他的授权类型为code 授权码模式,以及client_id,redirect_uri,state等信息,而此时页面也跳转到了用户代理的页面,让用户去决定是否要同意授权 :

    (C步骤)当用户输入用户名密码后点击授权并登录,服务器会先验证你输入的是否正确,如果正确,页面就会跳转到redirect_uri的地址中,而在这个过程中发生的变化是这样的,我们继续查看这时的URL地址:

    https://passport.csdn.net/account/login?oauth_provider=QQProvider&

    code=D185F3ED93E4F1B3C5F557E6112C7A9B&

    state=test

    (D步骤)我们可以看到授权并登录后它重定向到了我们指定的地址,而且还给予了一个code授权码,另外state状态还是在请求登录时的状态,在下一个步骤中,是客户端向授权服务器申请令牌,包含以下参数:

    • grant_type 表示授权模式,此处固定为authorization_code,必选
    • code 表示上一步获取到的授权码,必选
    • redirect_uri 表示重定向URI,必选
    • client_id 表示客户端ID,必选

    在使用腾讯开放平台时,它会要求有一个client_secrect,是对应你客户端ID的一个私钥,它也是在客户端注册时产生的,所以在使用QQ登录获取令牌时,也必须指定该选项:client_secret,具体的可以看腾讯的开发文档。那么实际上申请令牌的这个过程我们是看不到的,返回authorization code 后,我们会看到我们的客户端此时已经登录成功了。例如:

    POST /token HTTP/1.1

    Host: graph.qq.com/oauth2.0/token

    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_secret=fdhsjfdsj32jjfhjdk

    (E步骤)若以上返回成功,那么在E步骤中会返回如下信息:

    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"

    }

    里面包含了我们所需要的令牌access token以及有效期等信息。实际上在我们实际应用过程中,我们不止是到这里就结束了,我们会使用access token令牌再去请求资源服务器,获取可以被调用的资源,以及一些其他的操作。

      2、implicit(简化模式)

    简化模式用于获取访问令牌(但它不支持令牌的刷新),并对运行特定重定向URI的公共客户端进行优化,而这一些列操作通常会使用脚本语言在浏览器中完成,令牌对访问者是可见的,且客户端也不需要验证。具体流程如下:

    步骤解析:

    1. 客户端携带客户端标识以及重定向URI到授权服务器;
    2. 用户确认是否要授权给客户端;
    3. 授权服务器得到许可后,跳转到指定的重定向地址,并将令牌也包含在了里面;
    4. 客户端不携带上次获取到的包含令牌的片段,去请求资源服务器;
    5. 资源服务器会向浏览器返回一个脚本;
    6. 浏览器会根据上一步返回的脚本,去提取在C步骤中获取到的令牌;
    7. 浏览器将令牌推送给客户端。

    (A步骤)中需要用到的参数,注意在这里要使用"application/x-www-form-urlencoded"格式:

    • response_type 必选项,此值必须为"token"
    • client_id 必选项
    • redirect_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步骤)中返回的参数包含:

    • 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
    					

      3、resource owner password credentials(密码模式)

    密码模式适合建立在客户端与资源所有者具有信任关系的情况下,例如它是一个设备的操作系统或者具有很高权限的应用。这种模式用户要向客户端提供自己的用户名密码,从而达到向服务提供商索取授权。授权服务器在启动此类型时,要特别小心,只有在其他的授权方式不被允许的情况下才可以使用这种授权模式。流程如下:

    1. 客户端要求使用资源所有者的密码;
    2. 资源所有者给予用户名密码后,客户端向授权服务器发起申请令牌的请求;
    3. 授权服务器将令牌发放给客户端。

    步骤解析:

    (B步骤)所需参数:

    • grant_type 必选项 此值必须为"password"
    • username 必选项 用户名
    • password 必选项 密码
    • scope 可选项

    例如:

    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

        (C步骤)发放令牌:

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

      4、client credentials(客户端模式)

    客户端模式是4种模式中最简单的一种模式。客户端可以使用客户端凭据请求访问令牌(或者其他支持的认证方式),在这种模式中,客户端占据主导地位,它不需要用户的同意,可以直接向授权服务器索取令牌,严格来说,该模式并不存在授权的问题,流程如下:

    1. 客户端向授权服务器发起请求索要令牌;
    2. 授权服务器将令牌发放给客户端。

    步骤解析:

    (A步骤)中所需的参数::

    • grant_type 必选项 此值必须为client_crendentials
    • scope 可选项

    例如:

    POST /token HTTP/1.1

    Host: server.example.com

    Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW

    Content-Type: application/x-www-form-urlencoded

    grant_type=client_credentials

    (B步骤)授权服务器返回结果:

    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,

    "example_parameter":"example_value"

    }

    六、小结

        以以上内容简要介绍了关于OAuth授权的一些基础知识以及各种授权模式的具体流程。在后面的文章中,会结合本篇内容,陆续讲解如何在.net core中借助IdentityServer4 使用 OAuth 2.0授权。

    扫描二维码关注我的公众号,共同学习,共同进步!

  • 相关阅读:
    10月27号
    10月23号
    10月26号
    10月30号
    10月28号
    10月29号
    JAVA日报
    JAVA日报
    JAVA日报
    JAVA日报
  • 原文地址:https://www.cnblogs.com/Allen0910/p/8647935.html
Copyright © 2020-2023  润新知