OAuth 2.0 是一种让第三方网站在不用知道你密码的情况下,安全获取你数据的授权方法。它的核心思想就是用令牌(Token)代替密码。为了让你轻松理解,我们先认识 4 个“小角色”,再看最常用的授权码流程(Authorization Code Flow)。

核心概念

核心角色

授权码模式(Authorization Code Flow)

这是网上最常见、最安全的流程,比如你用微信登录某个新游戏。

D2 Diagram
qtopie.github.io

1. 客户端发起请求

你想玩一个新游戏。你点击了游戏网站上的 “用微信登录” 按钮。

2. 跳转到认证页面

游戏网站把你送到了微信的登录页面。这时候,网址里会带着游戏网站的身份证(Client ID)和跳回来的地址(Redirect URI)。

3. 用户同意授权

你在微信页面上输入账号密码登录,微信会问你:“你同意该游戏获取你的头像和名字吗?” 你点击“同意”。

4. 服务器发放授权码

微信确认你同意后,把你的浏览器送回游戏网站。同时,微信在网址后面塞了一个临时的授权码(Code)。

5. 客户端用授权码换令牌

游戏网站悄悄拿着这个授权码,在后台去找微信的认证服务器。微信核对无误后,把真正的访问令牌(Access Token)发给游戏网站。

6. 获取受保护的资源

游戏网站拿着访问令牌,去找微信的资源服务器。微信服务器检查令牌是真的,就把你的头像和名字给游戏网站,登录成功!

abstract protocol flow

为什么不直接发令牌,非要先发“授权码”?

因为步骤 4 的网址跳转是在浏览器上发生的,容易被坏人偷看。

游戏网站必须自己在后端实现“用 Code 换 Token”

微信、Google 等平台只负责提供接口,游戏网站需要自己编写代码去调用这个接口。为了安全,这一步流程和核心代码通常是这样实现的。

游戏网站需要做的 3 件事

1. 准备好“接头暗号”

游戏网站在后台代码里,必须存好两个关键信息(这是事先在微信/Google 开放平台注册得到的):

2. 后端提供一个“接收 Code”的接口

当用户在微信点击同意后,微信会把 Code 发送到游戏网站指定的网址(Redirect URI)。游戏网站的后端必须有一个接口来接收这个 Code。

3. 在后台发起网络请求(核心代码逻辑)

游戏网站的后端收到 Code 后,需要立即在服务器后台向微信的 Token 接口发送一个 HTTP POST 请求。拿 Python 举个例子,游戏网站后端的伪代码大致长这样:

import requests

# 1. 微信发给游戏网站的 Code
auth_code = request.get_argument("code")

# 2. 准备换取 Token 的参数
payload = {
    "client_id": "游戏的ID_123456",
    "client_secret": "游戏的私密密钥_abcde12345",  # 核心安全:Secret 留在后端,不走浏览器
    "grant_type": "authorization_code",
    "code": auth_code,
    "redirect_uri": "https://youxi.com"
}

# 3. 游戏网站自己发起请求,找微信换 Token
response = requests.post("https://qq.com", data=payload)

# 4. 解析拿到的 Token
tokens = response.json()
access_token = tokens.get("access_token")  # 拿到了真正的令牌!

真实开发中:通常不需要从零手写

虽然逻辑要由游戏网站实现,但现代开发很少有人真的从零去拼装 HTTP 请求。

如果你想自己动手写代码接入 OAuth2 认证,可以告诉我你准备用哪个编程语言(如 Java、Python、Go)或哪个平台(如微信、GitHub、Google 登录),我可以为你提供详细的代码模板!

拿到手的是什么:JWT Token 介绍

上面换回来的 access_token,在很多平台(如微信开放平台、Google、GitHub App)其实是一串 JWT(JSON Web Token)。理解它的结构,能帮你少踩很多坑。

JWT 长什么样

JWT 是一段用两个点 . 分成三部分的字符串:Header.Payload.Signature

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Payload 里常见的字段(Claims)

怎么验证一个 JWT(核心安全逻辑)

游戏网站拿到 JWT 后,不能相信它就直接用,必须校验签名:

  1. 把字符串按 . 拆成三段,前两段 Base64URL 解码得到 Header 和 Payload。
  2. 用相同的算法和密钥,对 Header.Payload 重新计算签名。
  3. 把算出来的签名和令牌里的第三段比对,一致才说明没被篡改
  4. 再检查 exp 是否过期、aud 是不是自己。
import base64, hmac, hashlib, json, time

def b64url_decode(s):
    s += "=" * (-len(s) % 4)
    return base64.urlsafe_b64decode(s)

def verify_jwt(token, secret):
    header_b64, payload_b64, signature_b64 = token.split(".")
    # 1. 重新计算签名
    expected = hmac.new(secret.encode(), f"{header_b64}.{payload_b64}".encode(),
                        hashlib.sha256).digest()
    actual = b64url_decode(signature_b64)
    assert hmac.compare_digest(expected, actual), "签名不符,令牌被篡改!"
    # 2. 解析并检查过期时间
    payload = json.loads(b64url_decode(payload_b64))
    assert payload["exp"] > time.time(), "令牌已过期!"
    return payload  # 校验通过,可以信任里面的用户身份

注意:用 对称密钥(HS256) 时,游戏网站和认证服务器共享同一把密钥;用 非对称密钥(RS256) 时,认证服务器用私钥签名,游戏网站只用公钥验签,更安全,也更适合多方验证。

为什么要用 JWT,而不是随便存个 session

但要注意:JWT 一旦签发,在 exp 之前都有效,无法主动吊销(除非额外维护黑名单),所以过期时间一般设得较短,配合 Refresh Token 使用。

其他授权模式

除了上面最常用的授权码模式,OAuth 2.0 还有三种应对不同场景的办法:

Grant Types

OAuth2 vs OpenIDConnect

Reference