OAuth(开放受权)是一个关于受权的开放标准,容许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。目前的版本是2.0版,本文将对OAuth2.0的一些基本概念和运行流程作一个简要介绍。主要参考RFC-6749。html
这里有两个典型的例子:git
评论
,结果发现须要有这个网站的帐号才能留言,此时有两个选择,一个是新注册一个此网站的帐号,二是点击经过github快速登陆。前者你以为过于繁琐,直接点击了github登陆,此时,OAuth的认证流程就开始了。经过引导跳转到github界面,会提示你是否受权该网站使用你的github用户信息,点击确认,跳转回原网站,发现已经使用你的github帐号默认注册了一个用户,并且还不须要用户名和密码,便捷高效。假若有一个云冲印的网站,能够将你存储在Google的照片冲印出来,用户为了使用该服务,必须让云冲印读取Google上的照片。为了拿到照片,云冲印必须得拿到一个用户的受权,如何获取这个用户受权呢?传统方法是用户将用户名和密码告诉云冲印,那么云冲印就能够自由无限制的访问了(至关于用户本身访问),这样显然是不行的,有几个严重的缺点:github
能够看出,OAuth就是为解决如上例子而诞生的。web
如下几个名词相当重要:json
Resource Owner
:资源全部者。即用户。Client
:客户端(第三方应用)。如云冲印。HTTP service
:HTTP服务提供商,简称服务提供商。如上文提到的github或者Google。User Agent
:用户代理。本文中就是指浏览器。Authorization server
:受权(认证)服务器。即服务提供商专门用来处理认证的服务器。Resource server
:资源服务器,即服务提供商存放用户生成的资源的服务器。它与认证服务器,能够是同一台服务器,也能够是不一样的服务器。Access Token
:访问令牌。使用合法的访问令牌获取受保护的资源。code
)。code
),请求访问令牌(access token
)。从运行流程不难看出,要获取access token
必须先获得用户受权(authorzation grant
),那么若是获取这么用户受权呢?OAuth 2.0定义了四种类型的受权类型:api
authorization code
)implicit
)resource owner password credentials
)client credentials
)authorization code
)受权码模式是功能最完整、使用最普遍、流程最严密的受权模式。浏览器
因为这是一个基于重定向的流,因此客户端必须可以与资源全部者的用户代理(一般是web浏览器)进行交互,而且可以从受权服务器接收传入的请求(经过重定向)。安全
User-Agent
)发送包括它的客户端标识符、请求的范围、本地状态和一个重定向URI,受权服务器在授予(或拒绝)访问权后将其发送给用户代理。redirection URI
),重定向到客户端,并附上一个受权码(code
)和一个前面提供的本地状态(state
)(若是有的话,则会原值返回)。重定向URI
,向受权服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。在发出请求时,受权服务器对客户端进行身份验证。请求参数包含受权代码、用于得到验证的受权代码的重定向URI、标识客户端身份的client id
和client secret
。access token
和刷新令牌refresh token
(可选)。接着来介绍下各个步骤所需的参数服务器
对于步骤A,客户端申请受权请求的URI,包含如下参数:app
response_type
受权类型。必选项,其值固定为code
。client_id
客户端id。必选项,用于标识受权服务器中已注册的客户端。redirect_uri
重定向URI。可选项,若是不填写则使用注册在受权服务器端与client_id对应的redirect_uri。scope
申请的权限范围,如read
或write
。可选项,若是申请的请求访问超出受权服务器定义的可操做范围则会失败。state
表示客户端当前状态。可选项,能够指定任意值,受权服务器会原封不动地返回这个值。eg:
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分钟,客户端只能使用该码一次,不然会被受权服务器拒绝。该码与client id
和重定向URI,是一一对应关系。state
若是客户端的请求中包含这个参数,认证服务器的回应也必须如出一辙包含这个参数。eg:
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,必选项。eg:
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
表示权限范围。可选项,若是与客户端申请的范围一致,此项可省略。eg:
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" }
implicit
)简化模式(implicit grant type)不经过第三方应用程序的服务器,直接在浏览器中向认证服务器申请令牌,跳过了"受权码"这个步骤,所以得名。全部步骤在浏览器中完成,令牌对访问者是可见的,且客户端不须要认证。具体步骤可参阅RFC6749 4.2节。
resource owner password credentials
)密码模式中,用户向客户端提供本身的用户名和密码。客户端使用这些信息,向"服务商提供商"索要受权。
在这种模式中,用户必须把本身的密码给客户端,可是客户端不得储存密码。这一般用在用户对客户端高度信任的状况下,好比客户端是操做系统的一部分,或者由一个著名公司出品。而认证服务器只有在其余受权模式没法执行的状况下,才能考虑使用这种模式。可参阅RFC6749 4.3节。
client credentials
)客户端模式(Client Credentials Grant)指客户端以本身的名义,而不是以用户的名义,向"服务提供商"进行认证。严格地说,客户端模式并不属于OAuth框架所要解决的问题。在这种模式中,用户直接向客户端注册,客户端以本身的名义要求"服务提供商"提供服务,其实不存在受权问题。可参阅RFC6749 4.4节。
前文提到了一个Github登陆留言的例子,假设咱们要使用OAuth2.0协议搭建一个网站,利用Github做为受权和资源服务器,实现第三方登陆功能。
(转载)现概况一下主要流程:
Github会对用户的权限作分类好比读取仓库信息的权限、写入仓库的权限、读取用户信息的权限、修改用户信息的权限等等。若是我想获取用户的信息,Github会要求我,先在它的平台上注册一个应用,在申请的时候标明须要获取用户信息的哪些权限,而且在申请的时候填写你的网站域名,Github只容许在这个域名中获取用户信息。
此时个人网站已经和Github之间达成了共识,Github也给我发了两张门票,一张门票叫作Client Id
,另外一张门票叫作Client Secret
。
用户进入个人网站,点击github登陆按钮的时候,个人网站会将Github给个人Client Id
交给用户,让他进入Github受权界面,若是此时用户没有登陆,Github会提示登陆(固然这不是OAuth2.0客户端部分应该关注的)。假设用户已经登陆Github,那么Github看到用户手中的门票,就知道是个人网站让他过来的,因而就把个人网站获取的权限摆出来,并询问用户是否容许网站获取这些权限。
// 用户登陆 github,协商 GET //github.com/login/oauth/authorize // 协商凭证 params = { client_id: "xxxx", redirect_uri: "http://my-website.com" }
若是用户赞成,在受权页面点击了确认受权后,页面会跳转到我预先设定的 redirect_uri
并附带一个盖了章的门票code
。
// 协商成功后带着盖了章的 code Location: http://my-website.com?code=xxx
这个时候,用户和 Github 之间的协商就已经完成,Github 也会在本身的系统中记录此次协商,表示该用户已经容许在个人网站访问上直接操做和使用他的部分资源。
第二步中,咱们已经拿到了盖过章的门票code
,但这个code
只能代表,用户容许个人网站从github上获取该用户的数据,若是我直接拿这个code
去github访问数据必定会被拒绝,由于任何人均可以持有code
,github并不知道code
持有方就是我本人。
还记得以前申请应用的时候github给个人两张门票么,Client Id
在上一步中已经用过了,接下来轮到另外一张门票Client Secret
。
// 网站和 github 之间的协商 POST //github.com/login/oauth/access_token // 协商凭证包括 github 给用户盖的章和 github 发给个人门票 params = { code: "xxx", client_id: "xxx", client_secret: "xxx", redirect_uri: "http://my-website.com" }
拿着用户盖过章的code
和可以标识我的身份的client_id
、client_secret
去拜访 github,拿到最后的绿卡access_token
。
// 拿到最后的绿卡 response = { access_token: "e72e16c7e42f292c6912e7710c838347ae178b4a" scope: "user,gist" token_type: "bearer", refresh_token: "xxxx" }
// 访问用户数据 GET //api.github.com/user?access_token=e72e16c7e42f292c6912e7710c838347ae178b4a
上一步github已经把最后的绿卡access_token
给我了,经过github提供的 API 加绿卡就可以访问用户的信息了,能获取用户的哪些权限在response
中也给了明确的说明,scope
为user
和gist
,也就是只能获取user
组和gist
组两个小组的权限,user
组中就包含了用户的名字和邮箱等信息了。
// 告诉我用户的名字和邮箱 response = { username: "barretlee", email: "barret.china@gmail.com" }
本文到此结束,介绍的整个流程比较简陋,具体细节仍是阅读 RFC6749 。