欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

理解OAuth 2.0 OAuth2.0 有大用 有大大用

作者: 阮一峰

日期: 2014年5月12日

OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版。

本文对OAuth 2.0的设计思路和运行流程,做一个简明通俗的解释,主要参考材料为RFC 6749

OAuth Logo

一、应用场景

为了理解OAuth的适用场合,让我举一个假设的例子。

有一个"云冲印"的网站,可以将用户储存在Google的照片,冲印出来。用户为了使用该服务,必须让"云冲印"读取自己储存在Google上的照片。

云冲印

问题是只有得到用户的授权,Google才会同意"云冲印"读取这些照片。那么,"云冲印"怎样获得用户的授权呢?

传统方法是,用户将自己的Google用户名和密码,告诉"云冲印",后者就可以读取用户的照片了。这样的做法有以下几个严重的缺点。

(1)"云冲印"为了后续的服务,会保存用户的密码,这样很不安全。

(2)Google不得不部署密码登录,而我们知道,单纯的密码登录并不安全。

(3)"云冲印"拥有了获取用户储存在Google所有资料的权力,用户没法限制"云冲印"获得授权的范围和有效期。

(4)用户只有修改密码,才能收回赋予"云冲印"的权力。但是这样做,会使得其他所有获得用户授权的第三方应用程序全部失效。

(5)只要有一个第三方应用程序被破解,就会导致用户密码泄漏,以及所有被密码保护的数据泄漏。

OAuth就是为了解决上面这些问题而诞生的。

二、名词定义

在详细讲解OAuth 2.0之前,需要了解几个专用名词。它们对读懂后面的讲解,尤其是几张图,至关重要。

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

(2)HTTP service:HTTP服务提供商,本文中简称"服务提供商",即上一节例子中的Google。

(3)Resource Owner:资源所有者,本文中又称"用户"(user)。

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

(5)Authorization server:认证服务器,即服务提供商专门用来处理认证的服务器。

(6)Resource server:资源服务器,即服务提供商存放用户生成的资源的服务器。它与认证服务器,可以是同一台服务器,也可以是不同的服务器。

知道了上面这些名词,就不难理解,OAuth的作用就是让"客户端"安全可控地获取"用户"的授权,与"服务商提供商"进行互动。

三、OAuth的思路

OAuth在"客户端"与"服务提供商"之间,设置了一个授权层(authorization layer)。"客户端"不能直接登录"服务提供商",只能登录授权层,以此将用户与客户端区分开来。"客户端"登录授权层所用的令牌(token),与用户的密码不同。用户可以在登录的时候,指定授权层令牌的权限范围和有效期。

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

四、运行流程

OAuth 2.0的运行流程如下图,摘自RFC 6749。

OAuth运行流程

(A)用户打开客户端以后,客户端要求用户给予授权。

(B)用户同意给予客户端授权。

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

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

(E)客户端使用令牌,向资源服务器申请获取资源。

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

不难看出来,上面六个步骤之中,B是关键,即用户怎样才能给于客户端授权。有了这个授权以后,客户端就可以获取令牌,进而凭令牌获取资源。

下面一一讲解客户端获取授权的四种模式。

五、客户端的授权模式

客户端必须得到用户的授权(authorization grant),才能获得令牌(access token)。OAuth 2.0定义了四种授权方式。

  • 授权码模式(authorization code)

  • 简化模式(implicit)

  • 密码模式(resource owner password credentials)

  • 客户端模式(client credentials)

六、授权码模式

授权码模式(authorization code)是功能最完整、流程最严密的授权模式。它的特点就是通过客户端的后台服务器,与"服务提供商"的认证服务器进行互动。

授权码模式

它的步骤如下:

(A)用户访问客户端,后者将前者导向认证服务器。

(B)用户选择是否给予客户端授权。

(C)假设用户给予授权,认证服务器将用户导向客户端事先指定的"重定向URI"(redirection URI),同时附上一个授权码。

(D)客户端收到授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。

(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步骤中,服务器回应客户端的URI,包含以下参数:

  • code:表示授权码,必选项。该码的有效期应该很短,通常设为10分钟,客户端只能使用该码一次,否则会被授权服务器拒绝。该码与客户端ID和重定向URI,是一一对应关系。

  • 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,必选项,且必须与A步骤中的该参数值保持一致。

  • 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步骤中,认证服务器发送的HTTP回复,包含以下参数:

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

从上面代码可以看到,相关参数使用JSON格式发送(Content-Type: application/json)。此外,HTTP头信息中明确指定不得缓存。

七、简化模式

简化模式(implicit grant type)不通过第三方应用程序的服务器,直接在浏览器中向认证服务器申请令牌,跳过了"授权码"这个步骤,因此得名。所有步骤在浏览器中完成,令牌对访问者是可见的,且客户端不需要认证。

简化模式

它的步骤如下:

(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部分包含了令牌。

根据上面的D步骤,下一步浏览器会访问Location指定的网址,但是Hash部分不会发送。接下来的E步骤,服务提供商的资源服务器发送过来的代码,会提取出Hash中的令牌。

八、密码模式

密码模式(Resource Owner Password Credentials Grant)中,用户向客户端提供自己的用户名和密码。客户端使用这些信息,向"服务商提供商"索要授权。

在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下,比如客户端是操作系统的一部分,或者由一个著名公司出品。而认证服务器只有在其他授权模式无法执行的情况下,才能考虑使用这种模式。

密码模式

它的步骤如下:

(A)用户向客户端提供用户名和密码。

(B)客户端将用户名和密码发给认证服务器,向后者请求令牌。

(C)认证服务器确认无误后,向客户端提供访问令牌。

B步骤中,客户端发出的HTTP请求,包含以下参数:

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

上面代码中,各个参数的含义参见《授权码模式》一节。

整个过程中,客户端不得保存用户的密码。

九、客户端模式

客户端模式(Client Credentials Grant)指客户端以自己的名义,而不是以用户的名义,向"服务提供商"进行认证。严格地说,客户端模式并不属于OAuth框架所要解决的问题。在这种模式中,用户直接向客户端注册,客户端以自己的名义要求"服务提供商"提供服务,其实不存在授权问题。

客户端模式

它的步骤如下:

(A)客户端向认证服务器进行身份认证,并要求一个访问令牌。

(B)认证服务器确认无误后,向客户端提供访问令牌。

A步骤中,客户端发出的HTTP请求,包含以下参数:

  • granttype:表示授权类型,此处的值固定为"clientcredentials",必选项。

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

上面代码中,各个参数的含义参见《授权码模式》一节。

十、更新令牌

如果用户访问的时候,客户端的"访问令牌"已经过期,则需要使用"更新令牌"申请一个新的访问令牌。

客户端发出更新令牌的HTTP请求,包含以下参数:

  • granttype:表示使用的授权模式,此处的值固定为"refreshtoken",必选项。

  • refresh_token:表示早前收到的更新令牌,必选项。

  • scope:表示申请的授权范围,不可以超出上一次申请的范围,如果省略该参数,则表示与上一次一致。

下面是一个例子。


     POST /token HTTP/1.1
     Host: server.example.com
     Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
     Content-Type: application/x-www-form-urlencoded

     grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA

(完)

珠峰培训

stuQ

留言(123条)

阮老师的文章都是精品,真正做到深入浅出。

留名,慢慢看~

今天培训老师讲了这部分,恰好阮老师写了这篇文章介绍,加深理解。

那什么,没看懂。能不能用位图。ASCII图看的很不习惯。谢谢

授权码模式这部分中的“E步骤中,客户端发送的HTTP回复,包含以下参数“这句话,是否应为”认证服务器发送的HTTP回复“?

本文关于state参数的解释,是语焉不详的。事实上,绝大多数的互联网中文文档对这个参数都语焉不详。我想,对于造成近期互联网上危害广泛的OAuth漏洞来说,众多中文技术资料对这个参数解释不到位,对这个参数的实现没有给出清晰的指导,也是成因的一部分。原文是这么说的:RECOMMENDED. An opaque value used by the client to maintain state between the request and callback. The authorization server includes this value when redirecting the user-agent back to the client. The parameter SHOULD be used for preventing cross-site request forgery as described in Section 10.12.如果阮老师只是翻译为什么“客户端状态”之类的话,还有什么“可以随便填”,这算不上一种到位的解释。首先,这个参数是“RECOMMENDED”,并非什么可有可无的东西,事实是很多厂商都实现成了可有可无,其次,这个参数是“SHOULD”,为啥“SHOULD”呢,因为会引发“CSRF”。

引用WhatDoesTheFoxSay的发言:

授权码模式这部分中的“E步骤中,客户端发送的HTTP回复,包含以下参数“这句话,是否应为”认证服务器发送的HTTP回复“?

谢谢指出,已经改过来了。

阮兄的博客又更新了,前几天买的《黑客与画家》昨天到了,很不错的书。

看了这么多OAuth的文章,阮老师的这篇是最好懂的,拜读了

说白了oauth就是一个网络版的usbkey

支付宝链接已失效

非常感谢老师的分享,收益了。。

引用Charles的发言:

本文关于state参数的解释,是语焉不详的。事实上,绝大多数的互联网中文文档对这个参数都语焉不详。我想,对于造成近期互联网上危害广泛的OAuth漏洞来说,众多中文技术资料对这个参数解释不到位,对这个参数的实现没有给出清晰的指导,也是成因的一部分。原文是这么说的:RECOMMENDED. An opaque value used by the client to maintain state between the request and callback. The authorization server includes this value when redirecting the user-agent back to the client. The parameter SHOULD be used for preventing cross-site request forgery as described in Section 10.12.如果阮老师只是翻译为什么“客户端状态”之类的话,还有什么“可以随便填”,这算不上一种到位的解释。首先,这个参数是“RECOMMENDED”,并非什么可有可无的东西,事实是很多厂商都实现成了可有可无,其次,这个参数是“SHOULD”,为啥“SHOULD”呢,因为会引发“CSRF”。

仔细一看,确实,如果state项不用动态数据的话会存在CSRF漏洞

(E)客户端使用令牌,向资源服务器申请获取资源。

令牌就可以?整个过程都没有用户名和密码的获得,那资源服务器又是如何确认用户的?

我是比较文学与世界文学的硕士生,希望您能联系我,探讨一下卡尔维诺。

授权码模式中,D步骤,文中说client_id是必选项,但是随后的例子中没有这项

收款主页下线啦

同ls的niannian
另外 granttype authorizationcode 都没加 _ 下划线

引用phi的发言:

那什么,没看懂。能不能用位图。ASCII图看的很不习惯。谢谢

話說,RFC本來就是純文字檔案,這樣的圖其實看了很親切。。。

引用smilexu的发言:

(E)客户端使用令牌,向资源服务器申请获取资源。

令牌就可以?整个过程都没有用户名和密码的获得,那资源服务器又是如何确认用户的?

使用oauth本来就是为了避免客户端获得用户名和密码…… 资源服务器如何用用户名密码来确认用户,就如何用令牌来确认用户。令牌就是一种包含(隐含)用户id的一次性的密码

如果客户端做一个假的验证授权页面,来套取用户,用户名和密码,是有可能的吧?

引用king的发言:

如果客户端做一个假的验证授权页面,来套取用户,用户名和密码,是有可能的吧?

我也有此疑问。weibo.com提供的都提示"请认准本页URL地址必须以 api.weibo.com 开头",这提示基本上没用。

协议中的 SHOULD,应该等同于 MUST 来对待。

引用jucelin的发言:

 

我也有此疑问。weibo.com提供的都提示"请认准本页URL地址必须以 api.weibo.com 开头",这提示基本上没用。

工商银行的网银在开通时要求用户自己说一句话,每次使用网银付款时网站会向用户出示这句话以证明网站的合法性。这个感觉要好些吧~

有两点不太明白
1.授权码授权里,为什么要两次传递重定向url呢?有什么好处?
2.D步骤里,传递的参数有Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW,什么作用呢?

懂了,Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW,应该是对于应用client的授权认证,这样就相当于有两层保护,一层是认证客户端,一层是认证用户,不过basic的加密方式,是不是不太安全呢?

请问一下,授权码code,其作用是什么?

引用suolaiwo的发言:

请问一下,授权码code,其作用是什么?

本质的作用是避免Access Token通过URL返回,有篇视频讲这个比较详细《[开放平台]一步一步理解OAuth2协议-全网首发》
http://edu.51cto.com/index.php?do=course&m=addlession&course_id=2035

请问你这个是使用什么框架实现的OAuth的相关服务器端的?

正在学习OAuth2,写得太好了!非常容易理解!

我想知道 如何 生成access_token ,refresh_token 。

引用hebidu的发言:

我想知道 如何生成access_token ,refresh_token 。

生成access_token ,refresh_token 很简单,取一唯一的随机信息再做BASE64编码即可,它本身不包含任何有效信息的;服务端把它和用户受权关联以校验其受权的有效性.

请问,OAuth2.0客户端认证模式怎么限制客户端到认证服务器申请权限的范围(Scope)?

通俗易懂!感觉如等到风来吹开京都雾霾,重见蓝天白云!

引导用户到授权界面,用户会先登录后授权,整个授权过程中没有提到究竟是为“谁”授权的啊? 那token是怎么和userid进行映射的呢?
我开始理解的是,用户同意授权后,会告诉授权服务器client_id等参数外还会有userid。

阮老师为啥只发文而不答复上面技术性的探讨呢?

引用jinlong的发言:

引导用户到授权界面,用户会先登录后授权,整个授权过程中没有提到究竟是为“谁”授权的啊? 那token是怎么和userid进行映射的呢?
我开始理解的是,用户同意授权后,会告诉授权服务器client_id等参数外还会有userid。

你要知道这个授权的目的是给第三方应用授权,让他有权利去获取用户放在服务器上的资源,所以你应该站在第三方应用的角度来看待这篇文章,你的目的就是获取用户
QQ空间里的图片,就这么理解吧,差不想为那个什么讯发广告

引用匆匆过客的发言:

 

仔细一看,确实,如果state项不用动态数据的话会存在CSRF漏洞

确实是这样的,很多时候大家都忽略了这个state参数存在的意义。企鹅家的OAuth2.0文档里倒是把这个参数说的很详细(非广告,实话实说)。

密码模式的例子中Request Header 中的 Authorization 是怎么来的?

文章写的不错,深入浅出,正好在找Oauth 2.0相关的介绍文章,有帮助,多谢!

引用yuandghn的发言:

 

确实是这样的,很多时候大家都忽略了这个state参数存在的意义。企鹅家的OAuth2.0文档里倒是把这个参数说的很详细(非广告,实话实说)。

确实,刚查了腾讯文档 "state 可选 client端的状态值。用于第三方应用防止CSRF攻击,成功授权后回调时会原样带回。"

拿到访问令牌(access token)后,是不是每次请求资源都必须附上访问令牌?OAuth2是不是只适合Http,基于OAuth2的都只能通过客户端轮询来获取最新状态而不能由服务端进行推送?

简化模式中:
C)假设用户给予授权,认证服务器将用户导向客户端指定的"重定向URI",并在URI的Hash部分包含了访问令牌。

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

(E)资源服务器返回一个网页,其中包含的代码可以获取Hash值中的令牌。
c处的hash有没有多余呢?谢谢

每次看到你这儿,东西就看明白了,简单清晰

具体的参考实现: http://git.oschina.net/shengzhao/spring-oauth-server

整合Spring Security与Oauth2 的完整代码.

描述的很好,不错。多谢了!

首先谢谢阮老师,学习了,我想问下token存在数据库还是session里好呢
存数据库是不是存一个过期时间(或者之类的),还有如果用户操作了,这个token就延长时间还是固定死的(几个小时就几小时几天就几天)之后过期再用refresh取

引用小正的发言:

首先谢谢阮老师,学习了,我想问下token存在数据库还是session里好呢
存数据库是不是存一个过期时间(或者之类的),还有如果用户操作了,这个token就延长时间还是固定死的(几个小时就几小时几天就几天)之后过期再用refresh取

我查了一些资料,基本捋顺了

感谢分享!

授权码模式,为什么不能通过一次请求获取访问令牌?为什么非要加上一次授权码请求呢?现在授权码的作用是指定访问范围,那为什么不可以把访问范围作为参数传给认证服务器通过一次请求获取访问令牌呢?

引用小超人的发言:

授权码模式,为什么不能通过一次请求获取访问令牌?为什么非要加上一次授权码请求呢?现在授权码的作用是指定访问范围,那为什么不可以把访问范围作为参数传给认证服务器通过一次请求获取访问令牌呢?

授权码模式比简化模式好在哪里呢?求路过大神指点

引用小超人的发言:

 

授权码模式比简化模式好在哪里呢?求路过大神指点

是安全性高吗?安全性高在哪里呢?求举例说明...

有一处clientcredentials,应该改为:client_credentials

引用jinlong的发言:

引导用户到授权界面,用户会先登录后授权,整个授权过程中没有提到究竟是为“谁”授权的啊? 那token是怎么和userid进行映射的呢?
我开始理解的是,用户同意授权后,会告诉授权服务器client_id等参数外还会有userid。

这个token可以是惟一的,也就是说,token唯一确定一个用户,像@feiniu5566 说的,客户端可以通过令牌请求用户信息,包括userid,所以没有必要额外发送。

写得十分清楚明白,多谢博主!

阮老师,授权码模式中A步骤中的redirect_uri写的是可选项,D步骤说的是必选项,这里是不是有矛盾

大学的时候接触淘宝API,也碰到:授权码模式, 但是知道看了这篇文章才系统的理解。。
谢了!

最近在搞第三方登入,虽然已经按文档弄好了,但是并不懂OAuth为何物,看了楼主介绍总结,很是详细,多谢楼主

最近要弄这个, 虽然几天了还是没什么进度,不过看了这篇文章感觉很详细,虽然并不懂。

灰常好,学到了很多,谢谢大拿

引用smilexu的发言:

(E)客户端使用令牌,向资源服务器申请获取资源。

令牌就可以?整个过程都没有用户名和密码的获得,那资源服务器又是如何确认用户的?

令牌就可以代表用户,资源服务器只负责提供资源

(C)假设用户给予授权,认证服务器将用户导向客户端事先指定的"重定向URI"(redirection URI),同时附上一个授权码。

我不明白这个URI是用来跳转到认证服务器的url 还是指向前面例子说的云冲印的图片 谢谢了^^

引用分崩离析的发言:

 

令牌就可以代表用户,资源服务器只负责提供资源

 


这个令牌是一个字符串,资源服务器如何鉴别这个字符串不是伪造的呢?需要资源服务器到认证服务器上去鉴别吗,还是两边约定一种鉴别机制(比如鉴别RMB一样)

引用h的发言:

 


这个令牌是一个字符串,资源服务器如何鉴别这个字符串不是伪造的呢?需要资源服务器到认证服务器上去鉴别吗,还是两边约定一种鉴别机制(比如鉴别RMB一样)

 

看了 RFC 文档
http://tools.ietf.org/html/rfc6749
明白了,还是需要在 AS 和 RS 之间有个交互。

7. Accessing Protected Resources

The client accesses protected resources by presenting the access
token to the resource server. The resource server MUST validate the
access token and ensure that it has not expired and that its scope
covers the requested resource. The methods used by the resource
server to validate the access token (as well as any error responses)
are beyond the scope of this specification but generally involve an
interaction or coordination between the resource server and the
authorization server.

引用h的发言:

 


这个令牌是一个字符串,资源服务器如何鉴别这个字符串不是伪造的呢?需要资源服务器到认证服务器上去鉴别吗,还是两边约定一种鉴别机制(比如鉴别RMB一样)


http://tools.ietf.org/html/rfc6749

Accessing Protected Resources

The client accesses protected resources by presenting the access
token to the resource server. The resource server MUST validate the
access token and ensure that it has not expired and that its scope
covers the requested resource. The methods used by the resource
server to validate the access token (as well as any error responses)
are beyond the scope of this specification but generally involve an
interaction or coordination between the resource server and the
authorization server.

少不了 RS 到 AS 之间交互认证 access_token,这个 Oauth 没有规定啊,可以随意发挥啊。

看了好几次,今天终于明白第一种模式了,谢谢老师 ^^

不错,好文章!

restful一头雾水,老师太深奥,还是不懂,泪奔啊

引用陈柏成的发言:

(C)假设用户给予授权,认证服务器将用户导向客户端事先指定的"重定向URI"(redirection URI),同时附上一个授权码。

我不明白这个URI是用来跳转到认证服务器的url 还是指向前面例子说的云冲印的图片谢谢了^^

AS完成授权之后 把授权码和state附在重定向URI之后 再把浏览器重定向回这个地址 redirection URI是client提供的一个地址 做这一步是为了让Client能够获得授权码

请教阮老师和路过大神:


我一直对implicit grant中的web-hosted client resource的作用感到疑惑
为什么需要先向web-hosted client resource请求一个包含JS代码html 然后再用JS来读取access_token in Fragment(Hash)最后获得access_token 为什么不直接在本地用JS代码来读取呢? 我在stackoverflow上看到人说这是重定向的常用做法 并没有涉及到安全性的考虑 但是为什么要这样做呢?

引用小超人的发言:

授权码模式,为什么不能通过一次请求获取访问令牌?为什么非要加上一次授权码请求呢?现在授权码的作用是指定访问范围,那为什么不可以把访问范围作为参数传给认证服务器通过一次请求获取访问令牌呢?

引用小超人的发言:

授权码模式比简化模式好在哪里呢?求路过大神指点

恩 先说为什么implicit grant不需要Authorization code吧 首先因为Authorization code和client secret是不会暴露给用户的 这个是服务器与服务器之间通信才需要的 所以implicit grant是通过user-agent(web browser)来与AS交互 你加上这两个东西之后 还是会暴露给用户看到的 所以没有必要在简化模式中增加他的复杂性

现在回到你问的 为什么授权码模式需要这个授权码 当然是为了安全性 首先在OAuth体系中access_token是作为访问获取资源的唯一凭据 如果在AS授权完成之后 直接通过重定向传回access_token 那么HTTP 302不是安全的 Attacker有可能会获取到access_token 但是如果只返回Authorization code 就算别人获得了也没什么卵用 因为Authorization code不能获取到资源 在client向AS请求access_token的过程中 是通过HTTPS来保证安全的 而且获得access_token是需要client secret与Authorization code一起的 Attacker知道了Authorization code但并不知道client secret 同样也不能获得到access_token 所以client与AS是有责任保护好client secret的

获得了access_token之后 向RS发起请求 RS其实会与AS交互 来校验access_token 所以你想直接伪造一个access_token 那也是不ok的

很透彻

突然想到漏说了一块 关于为什么不直接用HTTPS重定向回client
是因为不是所有client server都支持HTTPS~所以为了通用性 和安全性 才衍生出来这么一个Auth code

但是AS肯定是实现HTTPS的 所以在client向AS提起request 是木有问题的~

不太明白 为什么使用auth_code换取access_token的时候 还要传redirect_uri

最近在学习oauth2,看了阮老师的文章,很透彻,明白了.

写的很好,有参考价值

您好,想谈论下,在更新资源令牌的时候为什么要使用专门的更新令牌来更新资源令牌?为何不直接用资源令牌来更新资源令牌?

有些解释不够详细,看看这个tutorial更容易理解http://tutorials.jenkov.com/oauth2/index.html

最近在了解oauth,多谢详细讲解!

阮老师的文章还是非常好的。

阮老师,请问一下。
密码模式里的B步骤里
提到的Authorization: Basic 码是如何获得的呢?
在网上查到是userName:password的形式以Base64编码得到的,但是实际操作中得到的结果不一致。
所以想问下,该值是怎么编码得出的呢?

阮老师,请问一下。
密码模式里的B步骤里
提到的Authorization: Basic 码是如何获得的呢?
在网上查到是userName:password的形式以Base64编码得到的,但是实际操作中得到的结果不一致。
所以想问下,该值是怎么编码得出的呢?

为什么用户授权客户端访问自己的资源后,授权服务器给客户端返回一个code 然后客户端通过code再向授权服务器申请令牌 然后拿着令牌去访问资源 而不是 用户授权客户端访问自己的资源后 授权服务器直接返回令牌给客户端?为啥要费个二道手,先返回CODE呢

client secret 这个概念漏掉了吧

引用niannian的发言:

授权码模式中,D步骤,文中说client_id是必选项,但是随后的例子中没有这项

client_id的确应该是必选项,应该是阮老师遗漏了

引用jucelin的发言:

 

我也有此疑问。weibo.com提供的都提示"请认准本页URL地址必须以 api.weibo.com 开头",这提示基本上没用。

看新浪,腾讯的OAuth方案,客户端接入是需要申请,经过服务提供商审核的(会发放 client_id, cilent_secret),如果假冒一个钓鱼网站的话,审核是很有可能不通过的,甚至自己坑自己。
(当然审核可能不一定100%杜绝)

引用Euclidvi31的发言:

client secret 这个概念漏掉了吧

client secret是必须的,阮老师遗漏了

引用李先森的发言:

不太明白 为什么使用auth_code换取access_token的时候 还要传redirect_uri

redirect_uri是回调地址,客户端需要接受access_token,如果不跟认证服务器说好,认证服务器怎么给呢?

引用路人乙的发言:

 

看新浪,腾讯的OAuth方案,客户端接入是需要申请,经过服务提供商审核的(会发放 client_id, cilent_secret),如果假冒一个钓鱼网站的话,审核是很有可能不通过的,甚至自己坑自己。
(当然审核可能不一定100%杜绝)

 

楼上好像误解了别人的问题,jucelin的意思是一个网站提供例如新浪微博登陆,在引导用户到新浪认证时,其实时引导到一个虚假的地址。所以审核没用啊。
我觉得OAuth2.0对这个问题无解,因为如果既然会构造虚假地址,证明客户端就是一个危险站点。他能够引诱用户访问基本就成功了

引用popwar的发言:

有些解释不够详细,看看这个tutorial更容易理解http://tutorials.jenkov.com/oauth2/index.html

看了这个链接,理解更加深刻!

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

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

implicit模式中这2行解释描述好像有问题,按照图中的说明,“浏览器向资源服务器发出请求”,应该是浏览器向客户端的web服务器发出请求,而不是向资源服务器发出请求。

阮老师能不能形象的讲一下 OAuth,AspNetIdentity,OWin,IdentityServer3这四个的关系?以及OAuth的四种模式分别适合在什么场景下使用?一直比较迷糊,求解惑,谢谢

很清晰, 有参考价值

真是简洁明了,通俗易懂啊,谢谢博主分享。

一口气看完,第一感觉是,恩,似乎明白了,OAuth大概就是这样的东西啊!
但是回顾一遍,很多细节还是不明所以,而且持续想不通。


1、在第六章,授权码模式(authorization code)中,
先从通过“用户授权操作”得到了“认证码(Auth Code)”,
然后再用“认证码(Auth Code)”换取到了“令牌(Token)”,
为什么要分2步呢?直接通过“授权”取得“令牌”不就行了?

2、取到“令牌(Token)”的用途,是用它来“识别用户”并获取信息,
而且令牌又基本是明文传输的,
假设我无意中看到了其他用户的令牌,是不是可以直接拿来用呢?
难道不担心令牌被“冒用”吗?

求解惑。

(D)客户端收到授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。

在 【六、授权码模式】 中的这段翻译有误,原文中是说附上早先的授权码。这一步设置的重定向URI不一定非要和早先的相一致。

@ww:

关于为什么要多一步授权码的解释:http://stackoverflow.com/questions/13387698/why-is-there-an-authorization-code-flow-in-oauth2-when-i...

简单来说,是因为HTTP重定向没有body,只能通过url传参数,而url中的参数是不安全的,因为所有经过的路由器或服务器都能读取到url的信息,所谓的中间人攻击。

引用鱼肚的发言:

(D)客户端收到授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。

在 【六、授权码模式】 中的这段翻译有误,原文中是说附上早先的授权码。这一步设置的重定向URI不一定非要和早先的相一致。

自己给自己打脸。关于这段是我之前理解有误,请求access_token时确实需要早先的redirect_uri,以便服务器校验code和redirect_uri是否是一对

很感謝你的阮大大的文章,看了好多網路上的文章沒有看得太懂,看完你的終於明白了,特意說聲謝謝 :)

在研究 Google API 的时候,关于授权部分有一些疑惑,感谢您的博文。

第六节 授权码模式,D步骤的例子中没有client_id参数,与描述中的“必选项”矛盾?

每一次不小心浏览到阮大神的博客,都会被其提供的干货好文吸引!这样的文章越多越好,支持 阮sir

简单来说就是

在第三方服务那里, 加一个链接,链到服务器,在服务器输入账号密码之后, 服务器返给你一个 字符串 也就是授权码或者token之类都可以。然后拿着第三方服务拿着这个授权码 和服务器进行通信。
这个保护服务器上的账号密码,避免被过多的曝光,减少风险。

讲句真的,我估计我蠢笨啊,愣是觉得看不懂,还有没看明白为啥

@鱼肚:

而且code就可以不需要保密了,因为code是一次性的,只要用过一次就失效了,即使中间人拿到code也不能获取access_token,因为还需要client_id和client_secret,而这些信息是在资源服务器保存的。

引用newnius的发言:

 

这个token可以是惟一的,也就是说,token唯一确定一个用户,像@feiniu5566 说的,客户端可以通过令牌请求用户信息,包括userid,所以没有必要额外发送。

token 是第三方服务器向授权服务器用 code 获取的,那么授权服务器是怎么知道这个code是哪个用户授权的?
code也是唯一的,而且关联了用户?如果是这样,应该就不存在什么CSRF攻击

想问一下授权码模式中,为什么要有一个授权码?多一个来回? 为什么不直接返回一个token?

引用normalhefei的发言:

想问一下授权码模式中,为什么要有一个授权码?多一个来回? 为什么不直接返回一个token?

想真正了解OAUTH得多看看,这篇文章说是流水账也不为过,讲了一堆,只能让人了解了What和省略了很多细节How,至于评论中的一大堆Why就没有说明了。感觉典型的挖坑文章,挖完坑不填有时候还不如不挖。

ok,回到你的问题:服务器返回的授权码是一个客户端用于请求真正的accessToken的ticket。
为什么这么干:
因为服务器此时只是完成了:确认用户授权,但是至于用户确认授权的是不是真正clientId代表的app还不确定?
因为clientId那玩意公开的,用户都知道,所以如果我知道了clientId,我可以说我是你。
所以不安全,要做第二次验证。 第二次验证的就是在客户端后台完成的了,它得把clientId连同clientCredentail(secrectKey或者说密码)再加上获得的AuthorizationCode发给服务器做验证。
这才能获取最终使用的accessToken。

@ww:

第一个问题估计你知道答案了。

第二个问题是一个good point,答案是:所以不能用http,只能用https。参见 RFC6749:https://tools.ietf.org/html/rfc6749
Since requests to the authorization endpoint result in user
authentication and the transmission of clear-text credentials (in the
HTTP response), the authorization server MUST require the use of TLS
as described in Section 1.6 when sending requests to the
authorization endpoint.

看了这个文档,懂得了什么是auth2,但是对于JAVA中如何能够应用到项目中呢?

非常好的文章。

有看不明白的可以去慕课网上看看这个课程,更容易明白
http://www.imooc.com/learn/557

在“客户端模式”和“更新令牌”章节中,我发现写的是"grantType","clientcredentials","refreshtoken",看代码结果是"grant_type","client_credentials","refresh_token",这是作者不小心写错了还是说是一种书写约定,请问

redirecturl在授权码模式中a和e中可以不一样的吧,这两个地方的 url?

完全没有任何头绪,一点都看不懂

意思是懂了,具体怎么实现的还需要多加学习。

请问:
七、简化模式
简化模式(implicit grant type)不通过第三方应用程序的服务器,直接在浏览器中向认证服务器申请令牌,跳过了"授权码"这个步骤,因此得名。所有步骤在浏览器中完成,令牌对访问者是可见的,且客户端不需要认证。
中的:

(B)用户决定是否给于客户端授权。

这个用户怎么决定?用户是否需要登入?

还有:这种模式需不需要第三方应用程序的服务器登入用户(即输入用户名密码)?

引用路任戊的发言:

楼上好像误解了别人的问题,jucelin的意思是一个网站提供例如新浪微博登陆,在引导用户到新浪认证时,其实时引导到一个虚假的地址。所以审核没用啊。
我觉得OAuth2.0对这个问题无解,因为如果既然会构造虚假地址,证明客户端就是一个危险站点。他能够引诱用户访问基本就成功了

 

没看见state这个参数吗?这个就是防止虚假链接的

该篇文章里的authorization server翻译成中文难道不应该是授权服务器吗?认证服务器应该是authentication server才对吧?

引用qihaiyan的发言:

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

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

implicit模式中这2行解释描述好像有问题,按照图中的说明,“浏览器向资源服务器发出请求”,应该是浏览器向客户端的web服务器发出请求,而不是向资源服务器发出请求。

万分感谢,看了好久没看明白,看到你的解释终于明白了,应该是向客户端web服务器发出请求,获取从urlHash的js应该客户端做处理

谢谢阮老师,清晰讲解。

写的也没多清晰 里面那么多回调uri, 都没说清楚到底 都是回调哪儿的


普通分类: