OAuth2.0理解和用法

一、OAuth2.0是什么?

官方介绍是: OAuth 2.0授权框架允许第三方应用程序通过协调资源所有者和HTTP服务之间的审批交互,或允许第三方应用程序自己获得访问权限,从而获得对HTTP服务的有限访问。也就是授权别人(client)访问我们的资源。

OAuth 2.0 的标准是 RFC 6749 文件。该文件先解释了 OAuth 是什么。

OAuth 引入了一个授权层,用来分离两种不同的角色:客户端和资源所有者。…资源所有者同意以后,资源服务器可以向客户端颁发令牌。客户端通过令牌,去请求数据。

这段话的意思就是,OAuth 的核心就是向第三方应用颁发令牌。 然后,RFC 6749 接着写道:(由于互联网有多种场景,)本标准定义了获得令牌的四种授权方式(authorization grant )。

也就是说,OAuth 2.0 规定了四种获得令牌的流程。你可以选择最适合自己的那一种,向第三方应用颁发令牌。下面就是这四种授权方式。

授权码(authorization-code)
隐藏式(implicit)
密码式(password):
客户端凭证(client credentials)

注意,不管哪一种授权方式,第三方应用申请令牌之前,都必须先到系统备案,说明自己的身份,然后会拿到两个身份识别码:客户端 ID(client ID)和客户端密钥(client secret)。这是为了防止令牌被滥用,没有备案过的第三方应用,是不会拿到令牌的。

1.别人(client)是什么?

登录石墨文档可以输入账号密码登录,也可以选择微信登录,微信扫码确认后,就登录了石墨文档。石墨文档通过微信认证的方式实现了自身的认证登录。这个石墨文档就是client的角色(Role)。

2.什么时候需要让别人(client)访问我们的资源?

最常见的是微信授权登录,对client来说,是用户授权client拿到用户在微信上的信息,比如性别,唯一id。

3.我们怎么才能做到授权给别人访问我们的资源?

我们自己怎么获取自己的资源?我们登录后就可以获取到自己的账号信息等资源了。那么怎么给到别人?直接把我们的账号密码给第三者太不安全了。一个是自己的账号密码存在泄露的风险,一个是自己的账号权限太大,万一被别人删除了或者看到了不该看到的东西怎么办。

在使用阿里云的时候,我们可以给自己的账号开子账号,给子账号一些权限访问哪些服务(授权太复杂了),这样我们就可以达到最初的目的了: 让别人安全的访问我们的资源。

OAuth通过引入授权层并将client的角色与资源所有者的角色分离, 并且给client单独的凭证(access_token),client通过access_token获取有限的资源。

二、OAuth2.0定义的角色

1.resource owner

资源的拥有者,通常就是用户,比如登录的用户。

2.resource server

资源服务,提供资源的服务。需要access_token才允许被调用。比如微信api,通过access_token调用它可以获取到用户的性别等信息。

3.client

客户端,第三方客户端,被授权访问的应用。比如石墨文档通过微信登录的时候,石墨文档就是client角色,它要用户授权获取用户微信的信息。

4.authorization server

资源认证授权服务。用户登录到本服务后,可以选择授权给第三方。比如微信登录,微信认证服务就是authorization server的角色。可以颁发给client code,可以通过code换取access token. 可以通过access_token认证用户。

乍一看可能有点迷乱。站在登录用户的角度,简单的分为3个阵营:

  • 用户本身(resource owner),
  • 用户要登录的应用(client),
  • 用户的资源(resource server and authorization server). authorization server和resource server是一体的,一家的,比如都是微信的。这样清晰一些。只是对于微信内部,个人信息,朋友圈,公众号,小程序啥的,资源挺多,相当于多个resource server, 内部就分成了authorization server和多个resource server.

搞清楚这里面的角色后,再来看协议的流程。

三、OAuth2.0的协议流程

整体抽象协议流程如下。
在这里插入图片描述

A: client找用户(resource owner)请求授权,说你得让我获取你的微信昵称. 然后用户就看到微信授权页面(authorization server)显示是否允许client获取昵称。
B: 用户点确认,微信就会给client一个临时授权code。
C: client拿着上一步得到的授权code去找authorization server换一个access_token.
D: authorization server认证了client的参数,确认后,给client返回access_token.
E: client拿access_token去获取信息,比如获取用户昵称,头像。
F: client如愿以偿。

authorization grant授权发放模式是指client获取access_token的方式
官方给了4种,

  • authorization code: 授权码
  • implicit: 隐藏式
  • resource owner password: 用户的账号密码方式
  • client: client的id认证方式

当然,也可以自由扩展,能认证返回access_token就行。

grant是指授权给client,4中授权模式对应的是上图的BCD,即获取access_token的过程有4种方式。

1.access token存储方式?

access token就是访问资源的凭证,令牌。它的安全很重要。为了防止泄露被窃取,通常是client后端服务用token获取资源,是存储在client后台服务的,比如redis,mysql中,和用户关联存储。在浏览器上是体现不出的。那中间人就不能网络拦截到token。即access_token不应该在浏览器访问网络中出现。

2.四种获得令牌的获取流程

1.第一种方式:授权码

授权码(authorization code)方式,指的是第三方应用先申请一个授权码,然后再用该码获取令牌

这种方式是最常用的流程,安全性也最高,它适用于那些有后端的 Web 应用。授权码通过前端传送,令牌则是储存在后端,而且所有与资源服务器的通信都在后端完成。这样的前后端分离,可以避免令牌泄漏。

第一步,A 网站提供一个链接,用户点击后就会跳转到 B 网站,授权用户数据给 A 网站使用。下面就是 A 网站跳转 B 网站的一个示意链接。

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

上面 URL 中,response_type参数表示要求返回授权码(code),client_id参数让 B 知道是谁在请求,redirect_uri参数是 B 接受或拒绝请求后的跳转网址,scope参数表示要求的授权范围(这里是只读)。
在这里插入图片描述

第二步,用户跳转后,B 网站会要求用户登录,然后询问是否同意给予 A 网站授权。用户表示同意,这时 B 网站就会跳回redirect_uri参数指定的网址。跳转时,会传回一个授权码,就像下面这样。

https://a.com/callback?code=AUTHORIZATION_CODE

上面 URL 中,code参数就是授权码。
在这里插入图片描述

第三步,A 网站拿到授权码以后,就可以在后端,向 B 网站请求令牌。

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

上面 URL 中,client_id参数和client_secret参数用来让 B 确认 A 的身份(client_secret参数是保密的,因此只能在后端发请求),grant_type参数的值是AUTHORIZATION_CODE,表示采用的授权方式是授权码,code参数是上一步拿到的授权码,redirect_uri参数是令牌颁发后的回调网址。

在这里插入图片描述

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

{
   
       
  "access_token":"ACCESS_TOKEN",
  "token_type":"bearer",
  "expires_in":2592000,
  "refresh_token":"REFRESH_TOKEN",
  "scope":"read",
  "uid":100101,
  "info":{
   
   ...}
}

上面 JSON 数据中,access_token字段就是令牌,A 网站在后端拿到了。
在这里插入图片描述

2.第二种方式:隐藏式

有些 Web 应用是纯前端应用,没有后端。这时就不能用上面的方式了,必须将令牌储存在前端。RFC 6749 就规定了第二种方式,允许直接向前端颁发令牌。这种方式没有授权码这个中间步骤,所以称为(授权码)“隐藏式”(implicit)。

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

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

上面 URL 中,response_type参数为token,表示要求直接返回令牌。

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

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

上面 URL 中,token参数就是令牌,A 网站因此直接在前端拿到令牌。

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

在这里插入图片描述

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

3.第三种方式:密码式

如果你高度信任某个应用,RFC 6749 也允许用户把用户名和密码,直接告诉该应用。该应用就使用你的密码,申请令牌,这种方式称为"密码式"(password)。

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

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

上面 URL 中,grant_type参数是授权方式,这里的password表示"密码式",username和password是 B 的用户名和密码。

第二步,B 网站验证身份通过后,直接给出令牌。注意,这时不需要跳转,而是把令牌放在 J

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喜欢打篮球的普通人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值