OAuth 2.0 协议

OAuth 协议就是一种授权机制。它的目的是为第三方应用颁发一个有时效性的令牌 token,使得第三方应用能够通过该令牌获取相关的资源。常见的场景就是:第三方登录。当你想要登录某个论坛,但没有账号,而这个论坛接入了如 QQ、Facebook 等登录功能,在你使用 QQ 登录的过程中就使用的 OAuth 2.0 协议。

登录一个网站需要账号,授权登录成功会颁发token。令牌(token)与密码(password)的作用是一样的,都可以进入系统,但是有差异。

  1. 令牌是短期的,到期会自动失效,用户自己无法修改。密码一般长期有效,用户不修改,就不会发生变化。
  2. 令牌可以被数据所有者撤销,会立即失效。密码一般不允许被他人撤销。
  3. 令牌有权限范围(scope)。对于网络服务来说,只读令牌就比读写令牌更安全。密码一般是完整权限。

上面这些设计,保证了令牌既可以让第三方应用获得权限,同时又随时可控,不会危及系统安全。这就是 OAuth 2.0 的优点。

只要知道了令牌,就能进入系统。系统一般不会再次确认身份,所以令牌必须保密,泄漏令牌与泄漏密码的后果是一样的,所以令牌的有效期一般都设置得很短。

1. 角色

OAuth 2.0 协议中的一些角色,整个授权协议的流程都将围绕着这些角色。

角色描述
resource owner资源所有者,能够允许访问受保护资源的实体。如:用户等。
client客户端,使用资源所有者的授权代表资源所有者发起对受保护资源的请求的应用程序。如:web网站,移动应用等。
authorization server授权服务器,能够向客户端颁发令牌。
resource server资源服务器,托管受保护资源的服务器。
user-agent用户代理,帮助资源所有者与客户端沟通的工具,一般为 web 浏览器,移动 APP 等。

例如:用户想在A网站使用B网站的账号登录,A网站事先需要先在B网站注册,成为B网站的一个客户端。授权时,A网站通过浏览器跳到B网站,在B网站进行登录,浏览器在这里就是一个用户代理。登录成功后从B网站的授权服务器获取token,A网站带着token请求B网站的资源服务器获取用户信息。

上述例子中,资源所有者是用户;客户端是A网站,用户代理是浏览器,授权服务器和资源服务器都在B网站。

抽象协议流

2. 授权类型

OAuth 2.0 提供四种授权类型(authorization grant),即四种颁发令牌的方式。

不管哪一种授权方式,第三方应用(上述例子A网站)在申请令牌之前,都需要事先在系统(上述例子B网站)进行注册备案,说明自己的身份,然后会拿到两个身份识别码:客户端ID(client ID)和客户端密钥(client secret)。这是为了防止令牌被滥用,没有备案过的第三方应用,是不会拿到令牌的。

授权类型场景
授权码(authorization-code)与服务器端应用程序一起使用
隐藏式(implicit)与移动应用程序或Web应用程序(在用户设备上运行的应用程序)一起使用
密码式(password)与受信任的应用程序一起使用,例如服务本身拥有的那些
客户端凭证(client credentials)与应用程序API访问一起使用

2.1 授权码(authorization-code)

授权码(authorization code)方式是最常用的,因为它是为优化服务器端应用程序,其中,源代码不是公开露出,客户端密钥可保持机密性。这是基于重定向的流程,这意味着该应用程序必须能够与用户代理(即用户的Web浏览器)进行交互,并能够接收通过用户代理路由的API授权代码。

授权码方式需要第三方应用先申请一个授权码,然后再用该码获取令牌。授权码通过前端传送,令牌则是储存在后端,而且所有与资源服务器的通信都在后端完成。这样的前后端分离,可以避免令牌泄漏。

用户想登录A网站又没有A网站的账号,但是有B网站的账号,B网站又有提供授权服务,A网站又提前注册。那么当用户点击授权,A网站会向B网站请求用户信息,因为没有token,所以需要先获取token,获取token前又需要获取授权码。

获取授权码
A网站请求B网站的授权码

https://B.com/auth?
response_type=code&
client_id=CLIENT_ID&
redirect_uri=CALLBACK_URL&
scope=read&
state=lKJhU1

response_type=code:表示要求返回授权码(code)。
client_id:让 B 知道是谁在请求。
redirect_uri:是 B 接受或拒绝请求后的跳转网址。
scope:表示要求的授权范围(这里是只读)。
state:应用程序生成一个随机字符串,并将其包含在请求中。然后,在用户授权应用后检查是否返回了相同的值。这用于防止CSRF攻击。

想要获取授权码,B网站要确认用户信息,那么必须先登录B网站,然后询问是否同意给予 A 网站授权。用户表示同意,这时 B 网站就会跳回redirect_uri参数指定的网址。跳转时,会传回一个授权码。

https://A.com/redirect?
code=AUTHORIZATION_CODE&
state=lKJhU1

code=AUTHORIZATION_CODE:由授权服务器生成的授权码,生存期相对较短,通常会持续1到10分钟,具体取决于OAuth服务。
state:值将与应用程序最初在请求中设置的值相同该应用程序应检查重定向中的状态是否与它最初设置的状态匹配。这样可以防止CSRF和其他相关攻击。

获取token
A 网站拿到授权码以后,就可以在后端,向 B 网站请求令牌。

https://B.com/oauth/token?
grant_type=authorization_code&
code=AUTHORIZATION_CODE&
redirect_uri=CALLBACK_URL
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET&

grant_type=authorization_code:采用的授权方式是授权码。
code:上一步拿到的授权码。
redirect_uri:令牌颁发后的回调网址。
client_id:客户端id。
client_secret:客户端密码,让 B 确认 A 的身份。

B 网站收到请求以后,就会颁发令牌。具体做法是向redirect_uri指定的网址,发送一段 JSON 数据。

{
  "access_token":"access_token",
  "token_type":"bearer",
  "expires_in":3600,
  "refresh_token":"refresh_token",
  "scope":"read"
}

access_token字段就是令牌,A 网站在后端拿到了,可以在发出API请求时使用它。

授权码流程

2.2 隐藏式(implicit)

隐藏式(implicit)用于移动应用和网络应用程序(即应用程序在web浏览器中运行),其中客户端机密保密性无法得到保证。隐藏式也是基于重定向的流,但是访问令牌被提供给用户代理以转发给应用程序,因此它可能会暴露给用户和用户设备上的其他应用程序。同样,此流程不对应用程序的身份进行身份验证,直接向前端颁发令牌,这种方式没有授权码这个中间步骤,而是依靠重定向URI(已在服务中注册)来实现此目的。

隐式授予类型不支持刷新令牌。要求用户对应用程序进行授权,然后授权服务器将访问令牌传递回用户代理,然后将其传递给应用程序。

获取token
A 网站提供一个链接,要求用户跳转到 B 网站,授权用户数据给 A 网站使用。

https://B.com/oauth/authorize?
response_type=token&
client_id=CLIENT_ID&
redirect_uri=CALLBACK_URL&
scope=read

response_type=token:表示要求直接返回令牌。

用户跳转到 B 网站,登录后同意给予 A 网站授权。这时,B 网站就会跳回redirect_uri参数指定的跳转网址,并且把令牌作为 URL 参数,传给 A 网站。

https://A.com/callback#token=ACCESS_TOKEN

token:就是令牌,A 网站因此直接在前端拿到令牌。

注意,令牌的位置是 URL 锚点(fragment),而不是查询字符串(querystring),这是因为 OAuth 2.0 允许跳转网址是 HTTP 协议,因此存在"中间人攻击"的风险,而浏览器跳转时,锚点不会发到服务器,就减少了泄漏令牌的风险。

这种方式把令牌直接传给前端,是很不安全的。因此,只能用于一些安全要求不高的场景,并且令牌的有效期必须非常短,通常就是会话期间(session)有效,浏览器关掉,令牌就失效了。

隐藏式流程

2.3 密码式(password)

密码式(password)是使用资源所有者密码凭据授予类型,用户可以直接向应用程序提供其服务凭据(用户名和密码),该应用程序使用凭据从服务获取访问令牌。

获取token
A 网站要求用户提供 B 网站的用户名和密码。拿到以后,A 就直接向 B 请求令牌。

https://B.com/token?
grant_type=password&
username=USERNAME&
password=PASSWORD&
client_id=CLIENT_ID

grant_type=password:表示"密码式"。
username和password是 B 的用户名和密码。

B 网站验证身份通过后,直接给出令牌。注意,这时不需要跳转,而是把令牌放在 JSON 数据里面,作为 HTTP 回应,A 因此拿到令牌。

这种方式需要用户给出自己的用户名/密码,显然风险很大,因此只适用于其他授权方式都无法采用的情况,而且必须是用户高度信任的应用。

2.4 客户端凭证(client credentials)

客户端凭证(client credentials),适用于没有前端的命令行应用,即在命令行下请求令牌。

获取token
A 应用在命令行向 B 发出请求。

https://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 的身份。

B 网站验证通过以后,直接返回令牌。

这种方式给出的令牌,是针对第三方应用的,而不是针对用户的,即有可能多个用户共享同一个令牌。

3. 令牌的使用

A 网站拿到令牌以后,就可以向 B 网站的 API 请求数据了。

此时,每个发到 API 的请求,都必须带有令牌。具体做法是在请求的头信息,加上一个Authorization字段,令牌就放在这个字段里面。

curl -H "Authorization: Bearer ACCESS_TOKEN" \
"https://api.b.com"

ACCESS_TOKEN就是拿到的令牌。

4. 更新令牌

令牌的有效期到了,如果让用户重新走一遍上面的流程,再申请一个新的令牌,很可能体验不好,而且也没有必要。OAuth 2.0 允许用户自动更新令牌。

具体方法是,B 网站颁发令牌的时候,一次性颁发两个令牌,一个用于获取数据,另一个用于获取新的令牌(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用来让 B 确认 A 的身份。
refresh_token:用于更新令牌的令牌。

B 网站验证通过以后,就会颁发新的令牌。

参考:
OAuth 官网
OAuth 2.0 的一个简单解释
OAuth 2.0 的四种方式
OAuth 2简介
什么是OAuth 2.0授权码授予类型?
10 分钟理解什么是 OAuth 2.0 协议
一张图搞定OAuth2.0

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值