OAuth 2.0
OAuth 2.0 是一种授权机制,用来授权第三方应用,获取用户数据。第三方应用如果直接用密码登录服务提供商的服务器会存在风险。OAuth 2.0 使用令牌登录,服务提供商根据令牌的权限范围和有效期,向第三方应用开放用户的资料。
名词
Third-party application:第三方应用程序,比如第三方网站
HTTP service:HTTP服务提供商,比如微信
Resource Owner:资源所有者,比如用户
User Agent:用户代理,比如浏览器
Authorization server:认证服务器,即服务提供商专门用来处理认证的服务器
Resource server:资源服务器,即服务提供商存放用户生成资源的服务器。它与认证服务器,可以是同一台服务器,也可以是不同的服务器
流程
- 第三方应用申请授权
- 用户同意授权
- 第三方应用使用上一步获得的授权,向认证服务器申请令牌
- 认证服务器对第三方服务器认证后,颁发令牌
- 第三方应用使用令牌,向资源服务器申请获取资源
- 资源服务器确认令牌无误,同意第三方应用获得资源
令牌 & 密码
- 令牌是短期的,存在有效期,用户无法修改;密码是长期的,用户可以修改
- 令牌可以被用户撤销,立即生效
- 令牌有权限范围,密码登录享有用户全部权限
授权模式
第三方应用必须获得用户的授权才能获得令牌申请资源,OAuth 2.0 提供了 4 种授权模式。
- 授权码模式
- 简化模式
- 密码模式
- 客户端模式
第三方应用(客户端)申请令牌之前,必须到服务提供商系统备案,拿到客户端 ID 和客户端密钥。没有经过备案的第三方应用无法拿到令牌。
授权码模式
授权码模式指第三方应用先申请一个授权码,再用该授权码获取令牌。第三方应用服务器使用授权码和用户交互,用户判断是否进行授权;如果用户同意授权,第三方应用服务器再和认证服务器交互,获取令牌。
第三方应用 A 提供第三方登录跳转链接,用户点击后会跳转到认证服务器 B 网站,授权用户数据给 A
1
2
3
4
5https://b.com/oauth/authorize?
response_type=code&
client_id=CLIENT_ID&
redirect_uri=CALLBACK_URL&
scope=readB 要求用户登录并询问用户是否授权。如果用户同意授权,B 网站会跳转回
redirect_uri
指定的路径并传回一个授权码1
https://a.com/callback?code=AUTHORIZATION_CODE
A 网站拿到授权码后,可以在后端向 B 请求令牌
1
2
3
4
5
6https://b.com/oauth/token?
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET&
grant_type=authorization_code&
code=AUTHORIZATION_CODE&
redirect_uri=CALLBACK_URLB 网站颁发令牌。具体做法是向
redirect_uri
指定的网址发送一段json
数据1
2
3
4
5
6
7
8
9{
"access_token":"ACCESS_TOKEN",
"token_type":"bearer",
"expires_in":2592000,
"refresh_token":"REFRESH_TOKEN",
"scope":"read",
"uid":100101,
"info":{...}
}
到此,第三方应用程序拿到令牌,可以通过令牌申请用户数据。
简化模式
有些应用是纯前端的,没有后端,无法使用授权码模式。 OAuth 2.0 运行前端直接获取令牌。
A 网站提供第三方登录跳转链接,用户点击后会跳转到认证服务器 B 网站,授权用户数据给 A
1
2
3
4
5https://b.com/oauth/authorize?
response_type=token&
client_id=CLIENT_ID&
redirect_uri=CALLBACK_URL&
scope=readB 要求用户登录并询问用户是否授权。如果用户同意授权,B 网站会跳转回
redirect_uri
指定的路径并传回令牌1
https://a.com/callback#token=ACCESS_TOKEN
不安全,应用在安全要求不高的场景,并且令牌的有效期必须非常短,通常就是会话期(session)有效。
密码模式
如果高度信任某个应用,用户可以将用户名和密码提供给第三方应用,第三方应用使用密码申请令牌。适用于其他方式都无法使用,并且高度信任第三方应用的场景。
客户端模式
适用于没有前端的命令行模式,即在命令行下申请令牌。
使用令牌
第三方应用拿到令牌后,可以向服务提供商的 API 请求数据。每个 API 请求都必须携带令牌。具体做法在请求头部加入 Authorization
字段。
更新令牌
B 网站颁发令牌的时候,一次性颁发两个令牌,一个用于获取数据,另一个用于获取新的令牌(refresh token 字段)。令牌到期前,用户使用 refresh token 发一个请求,去更新令牌。
github 授权
客户端跳转链接:
1 | https://github.com/login/oauth/authorize? |
服务器处理:
1 | const clientID = '7e015d8ce32370079895' |