开放受权(OAuth)是一个开放标准,容许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。 —— 维基百科html
严格来讲,OAuth2 不是一个标准协议,而是一个安全的受权框架。其详细描述系统中不一样角色,用户,服务前端应用(如 API )以及客户端(如网站或APP)之间如何实现相互认证。前端
当前 OAuth 协议版本是 OAuth2.0,须要注意的是,OAuth2.0 并不向下兼容 OAuth1.0。git
在生活中,比较常见的 OAuth2 的使用场景是受权登陆,而且也普遍应用于 web、桌面应用和移动 APP 的第三方服务提供受权登陆验证机制,以实现不一样应用直接数据访问的权限。github
在 OAuth2 标准中定义了如下四种角色:web
表明受权客户端访问自己资源信息的用户(User);后端
表明意图访问受限资源的第三方应用。浏览器
表明托管了受保护的用户帐号信息的服务器,它与认证服务器,能够是同一台服务器,也能够是不一样的服务器;安全
表明验证用户身份而后为客户端派发资源访问令牌的服务器,即服务提供商专门用来处理认证的服务器;服务器
(配图来自阮一峰大佬)微信
大体流程归纳就是:
用户打开客户端之后,客户端要求用户给予受权。
用户赞成给予客户端受权。
客户端向受权服务器发送它本身的客户端身份标识和上一步中得到的受权(authorization grant),向认证服务器申请令牌。
认证服务器对客户端进行认证之后,确认无误,赞成发放令牌(access token),受权阶段至此所有结束。
客户端使用令牌,向资源服务器申请获取资源。
资源服务器确认令牌无误,赞成向客户端开放资源。
理解完上面整个流程之后,咱们再看看下面这张图,能更加清晰理解 OAuth2 的整个运行流程:
(配图来自公众号前端修仙之路)
从整个流程能够看出,在 B 步骤最为关键,即须要获取到用户对客户端的受权(如咱们在微信扫码登陆时,点击“肯定”按钮的步骤)。
有了这个受权之后,客户端才能拿到令牌,进而凭令牌向资源服务器获取资源。
另外,微信登陆的实现流程也相似:
(配图来自微信官方文档)
其总体流程为:
第三方发起微信受权登陆请求,微信用户容许受权第三方应用后,微信会拉起应用或重定向到第三方网站,而且带上受权临时票据 code
参数;
经过 code
参数加上 AppID
和 AppSecret
等,经过 API 换取 access_token
;
经过 access_token
进行接口调用,获取用户基本数据资源或帮助用户实现基本操做。
适合快速开发实施,代码量少,API须要被不一样APP使用,且每一个APP使用方式也不一样的状况。
学习和理解的成本比较大,而且 OAuth2 不是一个严格的标准协议,在实施过程当中更容易出错。
经过前面描述,能够知道OAuth 的核心就是向第三方应用颁发令牌。
OAuth 2.0 规定了四种得到令牌的流程。你能够选择最适合本身的那一种,向第三方应用颁发令牌。即如下四种受权方式:
注意:
无论哪种受权方式,第三方应用申请令牌以前,都必须先到系统备案,说明本身的身份,而后会拿到两个身份识别码:客户端 ID(client ID)和客户端密钥(client secret)。
这是为了防止令牌被滥用,没有备案过的第三方应用,是不会拿到令牌的。
即第三方应用先申请一个受权码,而后再用该码获取令牌。
适用于有后端的 Web 应用,受权码经过前端传送,令牌则是储存在后端,并且全部与资源服务器的通讯都在后端完成。这样的先后端分离,能够避免令牌泄漏。
这种方式也是最经常使用的流程,安全性最高。
(配图来自阮一峰大佬)
https://b.com/oauth/authorize?
response_type=code&
client_id=CLIENT_ID&
redirect_uri=CALLBACK_URL&
scope=read
复制代码
其中:
response_type
参数表示要求返回受权码(code);
client_id
参数让 B 知道是谁在请求;
redirect_uri
参数是 B 接受或拒绝请求后的跳转网址;
scope
参数表示要求的受权范围(这里是只读);
redirect_uri
参数指定的网址,就像下面这样:https://a.com/callback?code=AUTHORIZATION_CODE
复制代码
https://b.com/oauth/token?
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET&
grant_type=authorization_code&
code=AUTHORIZATION_CODE&
redirect_uri=CALLBACK_URL
复制代码
client_id
参数和 client_secret
参数用来让 B 确认 A 的身份( client_secret
参数是保密的,所以只能在后端发请求);
grant_type
参数的值是 AUTHORIZATION_CODE
,表示采用的受权方式是受权码;
code
参数是上一步拿到的受权码;
redirect_uri
参数是令牌颁发后的回调网址;
redirect_uri
指定的网址,发送包含令牌 access_token
字段的JSON数据,流程完毕。即隐藏受权码步骤,直接向前端发放令牌,也称受权码隐藏式。
(配图来自阮一峰大佬)
https://b.com/oauth/authorize?
response_type=token&
client_id=CLIENT_ID&
redirect_uri=CALLBACK_URL&
scope=read
复制代码
response_type
参数为 token
,表示要求直接返回令牌。
当用户赞成受权后,会跳转到 redirect_uri
参数指定的重定向地址,并将令牌做为 URL
参数传递给 A 网站。
https://a.com/callback#token=ACCESS_TOKEN
复制代码
token
参数就是令牌,A 网站所以直接在前端拿到令牌。
注意:
这里的令牌位置是 URL
锚点(即 #
号),而不是查询字符串,这是由于锚点不会发到服务器,避免泄露令牌的风险。
适用场景:
因为直接传递令牌不安全,所以经常适用在对安全要求不高的场景,而且令牌有效期很是短,例如会话期间(session)有效,关闭浏览器便失效。
即:对于信任的应用,能够携带约定的用户名和密码进行令牌申请。
https://oauth.b.com/token?
grant_type=password&
username=USERNAME&
password=PASSWORD&
client_id=CLIENT_ID
复制代码
grant_type
参数是受权方式,这里的 password
表示"密码式"; username
和 password
是 B 的用户名和密码。
适用场景:
风险较大,通常适用在对应用高度信任的状况。
即:给出凭证让对方确认并提供令牌。
https://oauth.b.com/token?
grant_type=client_credentials&
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET
复制代码
grant_type
参数等于 client_credentials
表示采用凭证式; client_id
和 client_secret
用来让 B 确认 A 的身份。
这种方式给出的令牌,是针对第三方应用的,而不是针对用户的,即有可能多个用户共享同一个令牌。
适用场景:
经过命令行请求令牌。
当网站获取到令牌之后,接下来每一个 API 请求都须要带上令牌,其作法是在请求的头信息中,将令牌添加 Authorization
字段中。
当令牌有效期到了,OAuth2 容许用户自动更新令牌,而不用让用户从新受权获取新令牌。
具体流程:
在 B 网站发放令牌时,一次性发放 2 个令牌,一个用于获取数据,一个用于获取新的令牌(refresh token
字段)。令牌到期后,用户使用 refresh token
发送请求去更新令牌:
https://b.com/oauth/token?
grant_type=refresh_token&
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET&
refresh_token=REFRESH_TOKEN
复制代码
grant_type
参数为 refresh_token
表示要求更新令牌; client_id
参数和 client_secret
参数用于确认身份; refresh_token
参数就是用于更新令牌的令牌。
B 网站验证经过之后,就会颁发新的令牌。
本文首发在 pingan8787我的博客,如需转载请联系本人。
Author | 王平安 |
---|---|
pingan8787@qq.com | |
博 客 | www.pingan8787.com |
微 信 | pingan8787 |
每日文章推荐 | github.com/pingan8787/… |
ES小册 | js.pingan8787.com |