0%

OAuth 2.0

Seidenschwanz_ZH-CN7486965726_1920x1080.jpg

OAuth 2.0

OAuth 2.0 是一种授权机制,用来授权第三方应用,获取用户数据。第三方应用如果直接用密码登录服务提供商的服务器会存在风险。OAuth 2.0 使用令牌登录,服务提供商根据令牌的权限范围和有效期,向第三方应用开放用户的资料。

名词

  • Third-party application:第三方应用程序,比如第三方网站

  • HTTP service:HTTP服务提供商,比如微信

  • Resource Owner:资源所有者,比如用户

  • User Agent:用户代理,比如浏览器

  • Authorization server:认证服务器,即服务提供商专门用来处理认证的服务器

  • Resource server:资源服务器,即服务提供商存放用户生成资源的服务器。它与认证服务器,可以是同一台服务器,也可以是不同的服务器

流程

pic

  1. 第三方应用申请授权
  2. 用户同意授权
  3. 第三方应用使用上一步获得的授权,向认证服务器申请令牌
  4. 认证服务器对第三方服务器认证后,颁发令牌
  5. 第三方应用使用令牌,向资源服务器申请获取资源
  6. 资源服务器确认令牌无误,同意第三方应用获得资源

令牌 & 密码

  • 令牌是短期的,存在有效期,用户无法修改;密码是长期的,用户可以修改
  • 令牌可以被用户撤销,立即生效
  • 令牌有权限范围,密码登录享有用户全部权限

授权模式

第三方应用必须获得用户的授权才能获得令牌申请资源,OAuth 2.0 提供了 4 种授权模式。

  • 授权码模式
  • 简化模式
  • 密码模式
  • 客户端模式

第三方应用(客户端)申请令牌之前,必须到服务提供商系统备案,拿到客户端 ID 和客户端密钥。没有经过备案的第三方应用无法拿到令牌。

授权码模式

授权码模式指第三方应用先申请一个授权码,再用该授权码获取令牌。第三方应用服务器使用授权码和用户交互,用户判断是否进行授权;如果用户同意授权,第三方应用服务器再和认证服务器交互,获取令牌。

pic

  1. 第三方应用 A 提供第三方登录跳转链接,用户点击后会跳转到认证服务器 B 网站,授权用户数据给 A

    1
    2
    3
    4
    5
    https://b.com/oauth/authorize?
    response_type=code&
    client_id=CLIENT_ID&
    redirect_uri=CALLBACK_URL&
    scope=read
  2. B 要求用户登录并询问用户是否授权。如果用户同意授权,B 网站会跳转回 redirect_uri 指定的路径并传回一个授权码

    1
    https://a.com/callback?code=AUTHORIZATION_CODE
  3. A 网站拿到授权码后,可以在后端向 B 请求令牌

    1
    2
    3
    4
    5
    6
    https://b.com/oauth/token?
    client_id=CLIENT_ID&
    client_secret=CLIENT_SECRET&
    grant_type=authorization_code&
    code=AUTHORIZATION_CODE&
    redirect_uri=CALLBACK_URL
  4. B 网站颁发令牌。具体做法是向 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 运行前端直接获取令牌。

  1. A 网站提供第三方登录跳转链接,用户点击后会跳转到认证服务器 B 网站,授权用户数据给 A

    1
    2
    3
    4
    5
    https://b.com/oauth/authorize?
    response_type=token&
    client_id=CLIENT_ID&
    redirect_uri=CALLBACK_URL&
    scope=read
  2. B 要求用户登录并询问用户是否授权。如果用户同意授权,B 网站会跳转回 redirect_uri 指定的路径并传回令牌

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

不安全,应用在安全要求不高的场景,并且令牌的有效期必须非常短,通常就是会话期(session)有效。

密码模式

如果高度信任某个应用,用户可以将用户名和密码提供给第三方应用,第三方应用使用密码申请令牌。适用于其他方式都无法使用,并且高度信任第三方应用的场景。

客户端模式

适用于没有前端的命令行模式,即在命令行下申请令牌。

使用令牌

第三方应用拿到令牌后,可以向服务提供商的 API 请求数据。每个 API 请求都必须携带令牌。具体做法在请求头部加入 Authorization 字段。

更新令牌

B 网站颁发令牌的时候,一次性颁发两个令牌,一个用于获取数据,另一个用于获取新的令牌(refresh token 字段)。令牌到期前,用户使用 refresh token 发一个请求,去更新令牌。

github 授权

客户端跳转链接:

1
2
3
https://github.com/login/oauth/authorize?
client_id=7e015d8ce32370079895&
redirect_uri=http://localhost:8080/oauth/redirect

服务器处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
const clientID = '7e015d8ce32370079895'
const clientSecret = '2b976af0e6b6ceea2b1554aa31d1fe94ea692cd9'

const Koa = require('koa');
const path = require('path');
const serve = require('koa-static');
const route = require('koa-route');
const axios = require('axios');

const app = new Koa();

const main = serve(path.join(__dirname + '/public'));

const oauth = async ctx => {
const requestToken = ctx.request.query.code;
console.log('authorization code:', requestToken);

const tokenResponse = await axios({
method: 'post',
url: 'https://github.com/login/oauth/access_token?' +
`client_id=${clientID}&` +
`client_secret=${clientSecret}&` +
`code=${requestToken}`,
headers: {
accept: 'application/json'
}
});

const accessToken = tokenResponse.data.access_token;
console.log(`access token: ${accessToken}`);

const result = await axios({
method: 'get',
url: `https://api.github.com/user`,
headers: {
accept: 'application/json',
Authorization: `token ${accessToken}`
}
});
console.log(result.data);
const name = result.data.name;
ctx.response.redirect(`/welcome.html?name=${name}`);
};

app.use(main);
app.use(route.get('/oauth/redirect', oauth));
app.listen(8080);

参考文献

  1. 理解OAuth 2.0
  2. OAuth 2.0 的四种方式
  3. GitHub OAuth 第三方登录示例教程