Oauth2.0
1、简介
OAuth(开放授权)是一个开放标准,允许用户授权第三方移动应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方移动应用或分享他们数据的所有内容。
OAuth 2.0 授权框架使得第三方可以获取对用户资源的访问(有限访问或者完全访问)。
举个例子:通过用户的允许,你开发的网页、app、小程序等可以去微信服务器获取你的头像,昵称,openid 等等。
传统授权方式,用户和第三方共享密码。缺点如下:
- 未来可能持续需要访问各种受限资源。所以第三方要存储用户密码,一般情况密码是明文,显然不安全。
- 第三方将可以访问所有的资源,而实际上它只应当有权限访问部分资源。
- 用户不能撤销单个第三方的访问权限。改密码,所有第三方都会失效。
术语
专业称呼 | 通俗叫法 |
---|---|
资源所有者 | 用户 |
资源服务器 | 保存用户信息的服务器并且能够验证令牌是否合法(比如说,微信服务器,保存你的微信头像等) |
客户端 | 第三方应用程序(比如说,你开发的网页、app、小程序) |
授权服务器 | 发送令牌给第三方的服务器(可以和资源服务器是同一个) |
2、授权码模式(重点)
(1)详细流程
基本流程:客户端现象用户发起授权申请,得到确认后,在向授权服务发起请求,请求同意后,获取到授权码,然后通过授权码去请求资源服务器,得到目标资源。
最常用的模式,微信、QQ、Github 登陆第三方网站就是这种模式。优点前后端分离,避免令牌泄露。
- 哔哩哔哩提供一个“微信登陆”的链接,用户点击跳转到微信授权服务器。
- 用户根据微信授权服务器提示登陆微信并确认授权给哔哩哔哩。
- 微信授权服务器返回用户代理(浏览器)一个授权码。
- 用户代理(浏览器)把这个授权码传给哔哩哔哩。
- 哔哩哔哩凭借授权码向微信授权服务器请求令牌。
- 微信授权服务器发送令牌给哔哩哔哩。
之后哔哩哔哩就可以带着令牌去微信资源服务器读取用户资料。
微信开放平台oauth2.0案例

(2)详解
授权码模式(authorization code)是功能最完整、流程最严密的授权模式。
(1)用户访问客户端,后者将前者导向认证服务器,假设用户给予授权,认证服务器将用户导向客户端事先指定的”重定向URI”(redirection URI),同时附上一个授权码。
(2)客户端收到授权码,附上早先的”重定向URI”,向认证服务器申请令牌:
GET /oauth/token?response_type=code&client_id=test&redirect_uri=重定向页面链接
请求成功返回code授权码,一般有效时间是10分钟。
(3)认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。
POST /oauth/token?response_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=重定向页面链接

下面来分别讲解其中的几个点
第三方引导用户跳转至认证服务器的授权页面
在引导跳转的时候需要携带如下的几个参数
- response_type:授权类型。授权码模式下,就固定为code
- app_id:第三方应用的标识id。
- redirect_uri:重定向uri,也就是在授权成功后认证服务器让用户重定向的地址。一般而言也就是当前用户在第三方应用中最初的请求地址
- scope:授权范围。可选内容,可以根据第三方应用和实现方的要求自行制定合适的值。
- state:透明的验证参数。RFC6749文档推荐认证服务器在重定向的时候应该原封不同的返还这个参数。注意,该参数严格来说应该是一个必须参数。用来防止CSRF攻击。也就是说用于让第三方服务器验证重定向回来的uri的确是认证服务器的行为而不是其他的攻击者伪造的。一般来说跳转到认证服务器的授权页面是走的https,但是认证服务器重定向到回调地址的时候可能走的就是http。此时code存在泄漏以及url存在被伪造的风险。那么第三方应用必须要有办法验证该回调是否的确由认证服务器发起,并且的确是之前自己的授权请求导致的回调。做法其实也不复杂,就是在session中保存一个随机值,作为state参数。认证服务器回调的时候带上该state参数,第三方应用验证该参数是否与自己session中的state参数值一致即可。如果认证的授权页面不是https加密的,那么在发出请求的时候,认证state参数可能会被窃取。那么这个时候还有另外一种做法。也就是第三方应用发送的是加密后的state参数,而认证服务器重定向的时候携带的是解密后的state参数。第三方应用只要在session中判断解密后的值是否与session的一致,也可以达到防止攻击的目的。这样,授权页面也就是可以走在普通的http之中了。
用户选择是否给予授权
这一步是一个用户行为。目前基本的做法都是让用户在授权页面上输入用户名和密码。为了保证安全性,这个页面需要由https来进行保护。当然,如果有其他的方式来保证用户名密码,以及认证的state参数不会泄露也是可以的。如果用户输入正确的用户名和密码,一般就确认为用户给予授权。
认证服务器生成code并且让用户重定向至指定的url
如果用户给予授权,则认证服务器需要生成一个唯一的授权码code。该code的时效性应该比较短,在5分钟以内比较合适。并且该code只能使用一次,下次就会失效。同时,该code与客户端的id,redirect-uri参数是一一对应的关系。认证服务器此时应该让用户重定向至一开始指定的redirect_uri。携带上state和code参数
第三方应用使用code到认证服务器处兑换令牌access token
第三方应用在验证过state参数的正确性后,接着就可以使用code到认证服务器处换取token。这一步,第三方应用需要携带上的参数有
- code:就是认证服务器给予的code参数
- appid:客户端的唯一标识
- redirect_uri:也就是第一步请求中的重定向参数。因为code实际上是与appid和redirect_uri一一对应的。所以用code换取令牌的时候也要携带上这两个参数
- grant_type: 授权模式,这里固定为”authorization_code”
- appkey:用于验证应用的身份。appid和appkey可以理解为应用自己的用户名和密码。
oauth2的服务器本身都是走https。所以都可以直接明文传输不需要考虑安全性问题。不过如果不是http的,也可以直接参数用户名密码登录的方式,就是给appkey进行md5运算。 关于为何不直接传递accesstoken的问题,是基于安全考虑。因为认证服务器是基于Https,而第三方应用可以是http的。如果在回调的时候直接带上accesstoken,就存在着泄露的问题。
认证服务器返回accesstoken
认证服务器在验证过参数的合法性后,生成一个全局唯一的token,并且返回给第三方应用。返回的内容采用json表示,返回的参数主要有
- access_token: 用于获取对应资源的令牌
- expires_time: 该令牌的有效期
- reflesh_token: 用户获取新的accesstoekn的token。由于accesstoken的有效期比较短,一旦失效,用户需要再走上面的流程是比较繁琐的。为了提升用户体验,可以使用reflesh_token来获取新的accesstoken。不过这个做法,已经有不同的实现方将这个返回参数去掉了。因为实际上reflesh_token也就意味着accesstoekn是永久有效的了。那和直接延长accesstoken的有效期也没有直接区别了。
3、简化模式(不推荐)
简化模式(implicit grant type)不通过第三方应用程序的服务器,直接在浏览器中向认证服务器申请令牌,跳过了”授权码”这个步骤,因此得名。所有步骤在浏览器中完成,令牌对访问者是可见的,且客户端不需要认证。
(1)客户端将用户导向认证服务器。
(2)用户决定是否给于客户端授权。
(3)假设用户给予授权,认证服务器将用户导向客户端指定的”重定向URI”,并在URI的Hash部分包含了访问令牌。
(4)浏览器向资源服务器发出请求,其中不包括上一步收到的Hash值。
(5)资源服务器返回一个网页,其中包含的代码可以获取Hash值中的令牌。
(6)浏览器执行上一步获得的脚本,提取出令牌。
(7)浏览器将令牌发给客户端。
请求url
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
4、密码模式
密码模式(Resource Owner Password Credentials Grant)中,用户向客户端提供自己的用户名和密码。客户端使用这些信息,向”服务商提供商”索要授权。在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下。一般不支持refresh token。
步骤说明:
(A)用户向客户端提供用户名和密码。
(B)客户端将用户名和密码发给认证服务器,向后者请求令牌。
(C)认证服务器确认无误后,向客户端提供访问令牌。
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
5、客户端模式
指客户端以自己的名义,而不是以用户的名义,向”服务提供商”进行认证。严格地说,客户端模式并不属于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