平时浏览网站的时候,我们一定对登陆这个操作非常熟悉,且深受其害。尤其是看个帖子或者复制段文本的时候,弹出来要你登陆(点名CSDN🐶)
我们都知道,HTTP 是无状态的协议(即 对于事务处理没有记忆能力,每次客户端和服务端会话完成时,服务端不会保存任何会话信息)。
每个请求都是完全独立的,因此服务端无法确认当前访问者的身份信息,无法分辨上一次的请求发送者和这一次的发送者是不是同一个人。服务器与浏览器为了进行会话跟踪(知道是谁在访问我),也为了获取用户信息&用户留存,就必须主动的去维护一个状态,这个状态用于告知服务端前后两个请求是否来自同一浏览器。
简单的会话状态跟踪一般通过 cookie 或者 session 去实现。但涉及到数据&信息获取,需要用更安全的方式来获得用户的授权,OAuth 2.0 就是这么一套授权标准协议。
我们可以这样理解,OAuth 2.0提供一种协议交互框架,让某个应用能够以安全地方式获取到用户的委派书,这个委派书在OAuth 2.0中就是访问令牌(access token),随后应用便可以使用该委派书,代表用户来访问用户的相关资源。
OAuth2.0 实际应用举例
我们平时在各平台使用微信登陆的场景应该很熟悉了,这些第三方登陆应该都是遵循的OAuth2.0协议(我猜)
不使用Oauth之前,网站要怎么获取你的授权信息呢? 最简单的就是让你输入微信账户和密码了(如下图)
但这种方式可太危险,密码随便暴露出去,权限也无法控制,用户相当于在裸奔,而使用OAuth 授权协议的话,相对来说就会安全的多了。
简单来说,用户登陆的时候,第三方应用会调起并跳转微信登陆,此时是在请求Oauth2.0授权登陆; 然后用户确认登陆后,微信通过网站提前申请好的回调路径通知网站(传过来一个token);网站通过这个token加上它提前申请好的一些信息向微信换取access_token
有了这个token,第三方网站就可以获取你同意的相关权限信息了。
下面具体介绍一下OAuth2.0的内容
概念定义
OAuth 定义了几个概念
- 资源拥有者 (Resource Owner):真实的用户(就是你),你需要授权相应的权限给接入的服务
- 客户端 (Client):即 要求接入的第三方应用(浏览器,第三方APP等)
- 资源服务器 (Resource Server):即拥有用户的信息的服务(谷歌,微信等)
- 授权服务器 (Authorization Server):提供授权服务,用于验证用户提供的信息是否正确并返回 access token 给客户端。
同时OAuth 提供了几种授权模式
- 授权码模式:常用的模式,安全性最高,资源属于用户个人,这种模式一般适用于有自己后台服务的应用,用户授权登陆后,客户端后台服务通过access_code&refresh_code 去访问获取信息
- 简化模式:适用于纯静态页面的应用(浏览器应用等,用户和客户端无法很好分离的场景)
- 应用授信模式:一般用于资源所有者是应用而不是个人,不需要经过跳转登陆这部操作(一些后台跑批任务等)
- 用户授信模式:这种是比较危险的模式,用户向客户端提供自己的用户名和密码,然后客户端向 "服务商提供商" 换取 access_token 。
授权码模式
授权码模式大致可以分为以下几个步骤:
- 用户在第三方应用登陆,第三方应用会请求资源服务器授权 URL,如:www.weixin.com/auth
- 客户端会重定向到一个授权页面
- 用户同意授权
- 资源服务器会重定向到应用的一个回调地址,如:www.client.com/recieve_tok…
- 资源服务器将一个code 异步发送到客户端提前申请好的回调地址上
- 客户端用
code换取access_token和refresh_token- 这个code是一次性的,后序客户端只使用access_token,快过期的时候用refresh_token续期
授权码详细过程
1、第三方应用(客户端)需要提前到资源服务商这边注册服务信息
我们以github oAuth app 为例子,我们要先去github提交信息
- 提供我们的homepage url
- 提供回调url,用户同意授权后会通过这个url将code返回
- 注册成功后,资源服务商github 会给你一个clientId和secret,这是你这个客户端的唯一身份标识
2、然后在用户点击登陆后,会调用资源服务商提供的url跳转到授权页面
- 这个 URL 指向 GitHub 的 OAuth 授权网址,带有两个参数:
client_id告诉 GitHub 谁在请求,redirect_uri是稍后跳转回来的网址。
https://github.com/login/oauth/authorize?
client_id=xxx
redirect_uri=http://localhost:8080/oauth/redirect
3、用户登陆后,选择运行的权限
4、GitHub 就会重定向到redirect_uri指定的跳转网址,并且带上授权码
5、客户端获得这个授权码后会请求资源服务商的授权url获取access_code和refresh_code(后台执行,用户不感知)
6、后序客户端请求在header里带上access_code进行操作
在 access_token 没有失效的前提下,可通过 access_token 可以访问平台服务端提供的资源。另外如果还提供了 refresh_token ,在 access_token 失效的情况下,可以通过 refresh_token 再次去获取有效的 access_token 。
简化模式
在某些场景下,应用程序运行在用户端(客户端和资源所有者两个角色是合在了一起),比如浏览器JS应用程序。
这种情况下一般适用简化模式,即不通过第三方应用程序的后台服务器,直接在浏览器中向认证服务器申请令牌。所有步骤在浏览器中完成,当在浏览器中回调的网页会打开后,access token 直接在浏览器的地址栏中就能看见,这是一种不安全的模式,容易造成 access_token 的泄露。
简化模式大致可以分为以下几个步骤:
-
客户端将用户跳转到认证服务器的url。
-
用户同意给客户端授权。
-
认证服务器将用户重定向到客户端指定的URL,并在 URI 的 Hash 部分包含了访问令牌(access_token,授权模式是code)
-
浏览器将令牌发给客户端(可以直接提取出来)
这种模式下,省去了客户端后台根据code换取access_code 的流程,这种模式不太安全,不推荐
PS. 对于各种模式下的重定向请求类型下面这种,资源服务商返回这个请求结果,客户端会跳转到Location对应的地址。
HTTP/1.1 302 Found
Location: http://example.com/cb#
access_token=2YotnFZFEjr1zCsicMWpAA&
state=xyz&
token_type=example&
expires_in=3600&
scope=read write
应用授信模式
在下面这两种情况下,一般适用应用守信用模式
- 资源所有者角色不参与授权交互
- 应用程序角色本身就是资源所有者
这种情况下的授信其实也相对简单
- 客户端尝试获取在资源服务器上的信息,直接向授权服务器申请访问令牌,并提供自己的授信凭证(client id/secret)。
- 在申请请求中,应用程序指定使用client credentials授权方式。
- 在授权服务器,服务器对其client credentials校验成功后,授权服务器直接颁发一个访问令牌给应用程序。
- 应用程序在拿到访问令牌之后,向资源服务器申请用户的资源信息
这个授权流程被称为应用授信模式,其命名原因是由于应用程序是通过自己的授信凭证(client id/secret)直接向授权服务器申请访问令牌。这种模式一般用在可信的应用程序。
和简化模式一样,授权服务器无需颁发刷新令牌给应用程序,原因很简单,应用程序想要的话,直接再调用授权服务器一次即可。
用户授信模式
这种模式其实就是密码登陆模式,流程如下
- 用户向客户端提供用户名和密码。
- 客户端将用户名和密码发给认证服务器,向后者请求令牌。
- 认证服务器确认无误后,向客户端提供访问令牌。 这种一般只会用于可信任的应用(第一方应用)
模式选择
要怎么选择合适鉴权方式,网上看到一张图感觉还比较形象
PS. use-agent模式就是浏览器Js这类的应用