我们在登录网站时,很多网站除了提供用户名密码或手机号登录的方式外,还提供了第三方登录的方式(使用QQ、微信、微博登录),用户无需注册便可登录网站。如图:
在实现第三方登录时,通常采用OAuth 2.0标准的授权码模式。
OAuth 2.0 简介OAuth 2.0 是RFC 6749文件中定义的一种标准,也是目前最流行的授权机制,用来授权第三方应用,获取用户数据。
OAuth 引入了一个授权层,用来分离两种不同的角色:客户端和资源所有者。......资源所有者同意以后,资源服务器可以向客户端颁发令牌。客户端通过令牌,去请求数据。
OAuth 2.0 的核心就是向第三方应用颁发令牌。
令牌与密码
令牌(token)与密码(password)的作用是一样的,都可以进入系统,但是有三点差异:
- 令牌是短期的,到期会自动失效,用户自己无法修改。密码一般长期有效,用户不修改,就不会发生变化。
- 令牌可以被数据所有者撤销,会立即失效。密码一般不允许被他人撤销。
- 令牌有权限范围(scope),可以限制令牌持有者使用数据的范围。密码一般是完整权限。
令牌既可以让第三方应用获得权限,同时又随时可控,不会危及系统安全。这就是OAuth 2.0 的优点。
四种授权模式
OAuth 2.0 规定了四种获得令牌的流程:
- 授权码(authorization code)
- 隐藏式(implicit)
- 密码式(password)
- 客户端凭证(client credentials)
注意,不管哪一种授权模式,第三方应用申请令牌之前,都必须先到系统备案,说明自己的身份,然后会拿到两个身份识别码:客户端 ID(client ID)和客户端密钥(client secret)。这是为了防止令牌被滥用,没有备案过的第三方应用,是不会拿到令牌的。
授权码模式授权码(authorization code)模式的特点就是第三方应用先申请一个授权码,然后再用该码换取令牌。
这种方式是最常用的流程,安全性也最高,它适用于那些有后端的 Web 应用。授权码通过前端传送,令牌则是通过后端传送。这样的前后端分离,可以避免令牌泄漏。
OAuth 2.0 授权码模式中定义了五种角色:
- 资源所有者:用户
- 资源服务器:存储用户信息的服务器
- 授权服务器:提供授权码和令牌的服务器
- 客户端(第三方应用):向用户申请授权,访问用户信息的应用
- 代理端:通常是浏览器
例如,用户A登录哔哩哔哩网站时,选择QQ方式登录,那么,资源所有者就是指用户A,资源服务器和授权服务器就是QQ提供的服务器,第三方应用就是B站。
资源服务器和授权服务器可以为同一台服务器,也可以为不同的服务器,但这两种角色肯定属于同一方。
到底谁是第三方?
前面在背景中提到,用户使用第三方登录的方式(QQ)登录B站,从这个角度看,第三方是QQ;而在授权码定义中,第三方应用又是指B站。
我认为,背景中提到的“第三方登录”其实应该称为“其他方式登录”;而授权码中的第三方就是指向用户申请授权并获取用户信息的应用。
授权流程
核心流程如图所示:
核心流程
具体流程如下:
1.用户访问B站(https://www.bilibili.com/),点击登录按钮,然后选择QQ登录。
2.用户点击“QQ登录”后,B站会把网页跳转到QQ系统提供的用户授权页面,示意URL如下:
https://graph.qq.com/oauth2.0/show?response_type=code&client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read
- response_type:申请授权类型,“code”为授权码模式
- client_id: B站在QQ平台备案后分配的客户端ID,该参数是让QQ知道谁在请求
- redirect_uri:用户同意或拒绝授权后跳转回B站的地址
- scope:申请的授权范围
3.用户同意授权后,QQ授权服务器生成授权码,然后把网页跳转回redirect_uri参数指定的网址。跳转时会携带授权码参数,示意URL如下:
https://www.bilibili.com/callback?code=AUTHORIZATION_CODE
- code:授权码
4.B站拿到授权码后,从系统后端向QQ授权服务器的令牌接口发送一个请求,用授权码换取令牌。示意请求如下:
https://graph.qq.com/oauth2.0/token?client_id=CLIENT_ID&client_secret=CLIENT_SECRET&grant_type=authorization_code&code=AUTHORIZATION_CODE
- client_id: B站在QQ平台备案后分配的客户端ID
- client_secret: B站在QQ平台备案后分配的客户端密钥(client_secret参数是保密的,因此只能在后端发请求)
- grant_type:授权类型,“authorization_code”代表授权码模式
- code:拿到的授权码
5.QQ授权服务器接收到请求后,生成访问令牌(访问令牌(access_token)必须,刷新令牌(refresh_token)可选),然后返回JSON数据。示意JSON如下:
{
"access_token": "ACCESS_TOKEN",
"token_type": "bearer",
"expires_in": 2592000,
"refresh_token": "REFRESH_TOKEN",
"scope": "read",
"uid": 100101
}
6.B站拿到访问令牌后,就可以请求QQ资源服务器提供的用户信息接口,获取用户数据。