OAuth 2.0
Oauth 2.0
Oauth 2.0是Oauth的最新版本,是目前主流的授权机制。那么它在哪里使用呢?答案就是第三方的授权登录。主流的互联网网站除了支持用户名+密码和手机号+验证码登录之外,一般还会有微信、QQ、Github登录等,国外常见的有Facebook、Twitter、Instagram、google,一些公司接入一些第三方服务商的系统的时候,还会要求通过企业邮箱进行授权登录,这些都是通过Oauth 2.0进行授权,OIDC进行认证,来实现第三方登录的。
授权第三方应用进入系统后,它会产生一个短期的进入令牌(Access Token),用来代替密码,供第三方应用使用。
为什么需要 Oauth 2.0
假设都是通过账号+密码登录网站,当你在一个网站A要使用一个云盘中的信息,那么用账号+密码在网站A登录,你的凭据就会被网站A知道,那么你的云盘数据就可能泄露。这个时候提出一种不需要输入账号密码又能获取在云盘中的资源,为了解决确认身份的问题,就产生了通过Oauth 授权,给一个短期的凭据,既不会让你的凭据泄露也可以让你暂时登录获取相关资源,凭据过期后就没法获取你的相关资源
Oauth 2.0 Structure
有四个主要的角色:
- 资源拥有者(Resource Owner):终端用户,拥有受保护资源(如用户数据、照片等)的所有权,通过授权同意客户端访问其资源(例如用微信登录第三方App时点击"允许")。
- 客户端(Client):代表用户访问资源的第三方应用(如网站A/B/C/D或移动App)。必须先在授权服务器注册,获取client_id等凭证。分为机密客户端(能安全存储密钥,如后端服务)和公开客户端(无法保密密钥,如前端应用)。
- 授权服务器(Authorization Owner):验证用户身份(如跳转登录页面)。管理用户授权流程(如询问用户是否同意授权)。颁发访问令牌(Access Token)和刷新令牌(Refresh Token)。
- 资源服务器(Resource Server):存储并保护用户资源(如微信存储用户个人信息、GitHub存储代码)。通过验证客户端提供的Access Token决定是否返回资源。通常与授权服务器分离,但可同属一个系统(如微信的授权和资源API在同一平台)。
Oauth 2.0 的四种授权类型
Oauth 2.0 规定了四种授权类型:
- 授权码(authorization-code)
- 隐藏式(implicit)
- 密码式(password):
- 客户端凭证(client credentials)
1. 授权码
第三方应用先申请一个授权码,在用该码获取令牌
- 第一步,用户跳转授权
- 前端生成授权链接,用户点击后跳转至授权服务器(如Google/OAuth服务商)
- https://b.com/oauth/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read(例)
- 用户登录并同意授权后,授权服务器返回授权码到redirect_url
- https://a.com/callback?code=AUTHORIZATION_CODE(例)
- 第二步,后端用授权码换取令牌
- 用code+client_secret向授权服务器请求access_token
- https://b.com/oauth/token?client_id=CLIENT_ID&client_secret=CLIENT_SECRET&grant_type=authorization_code&code=AUTHORIZATION_CODE&redirect_uri=CALLBACK_URL(例)
- 授权服务器返回access_token和refresh_token
example
{
"access_token":"ACCESS_TOKEN",
"token_type":"bearer",
"expires_in":2592000,
"refresh_token":"REFRESH_TOKEN",
"scope":"read",
"uid":100101,
"info":{...}
}
- 第三步,API调用
- 后端存储access_token,并在访问资源服务器时带上
PS:
- 授权码仅一次性有效,防止中间人攻击。
- client_secret 仅后端可见,避免泄露。
- refresh_token 可换取新 access_token,避免用户频繁授权。
2. 隐藏式
允许直接向前端颁发令牌。这种方式没有授权码这个中间步骤,所以称为(授权码)“隐藏式”(implicit)
-
第一步,前端直接请求令牌
- 前端跳转至授权服务器,response_type=token:
https://auth-server.com/authorize? response_type=token& client_id=YOUR_CLIENT_ID& redirect_uri=https://your-app.com/callback& scope=read_profile
- 用户授权后,授权服务器直接返回 access_token 到 redirect_uri 的 URL 锚点(#):
- 前端跳转至授权服务器,response_type=token:
https://yourapp.com/callback#access_token=TOKEN&expires_in=3600
-
前端JS解析 access_token(锚点不会发送到服务器,减少泄露风险)。
-
API 调用
- 前端直接使用 access_token 访问 API:
fetch("https://api.resource-server.com/data", { headers: { "Authorization": "Bearer ACCESS_TOKEN" } });
- 前端直接使用 access_token 访问 API:
PS:
- 令牌直接暴露给前端,可能被恶意JS窃取。
- 必须设置短有效期(如1小时),避免长期风险。
- 仅适用于低敏感度场景(如天气API)。
3. 密码式
-
用户直接输入账号密码
-
前端收集用户密码,直接发送给后端(不能存储!)。
-
后端向授权服务器请求令牌:
-
授权服务器返回 access_token。
-
POST https://auth-server.com/token
grant_type=password&
username=USERNAME&
password=PASSWORD&
client_id=YOUR_CLIENT_ID
PS:
- 用户需明文提供密码,仅限受信任应用(如公司内部工具)。
- 必须使用HTTPS,防止中间人窃取密码。
- 不推荐公开应用使用,风险极高!
4. 客户端凭证
- 应用直接用 client_id 和 client_secret 获取令牌
POST https://auth-server.com/token
grant_type=client_credentials&
client_id=YOUR_CLIENT_ID&
client_secret=YOUR_CLIENT_SECRET
- 授权服务器返回 access_token(仅用于该应用,不关联用户)。
PS:
- 无用户参与,仅限服务端使用(如定时任务、微服务通信)。
- 不能用于用户数据访问,仅限应用级权限。
Oauth 2.0 Flow
流程:
-
用户在客户端(如网站A)点击“用微信登录”。
-
客户端将用户重定向到授权服务器的授权端点(如微信的OAuth页面),并携带以下参数:
-
client_id: 客户端注册时获得的ID。
-
redirect_uri: 授权成功后回调的URI。
-
scope: 请求的权限范围(如读取用户信息)。
-
state: 随机字符串,防止CSRF攻击。
-
-
用户在授权服务器登录(如输入微信账号密码),并确认是否同意客户端请求的权限。
-
授权服务器将用户重定向回客户端的redirect_uri,并在URL中携带一个短期有效的code(授权码)和state。
-
客户端后端(非前端!)向授权服务器的令牌端点发送请求,包含:
-
code: 上一步获取的授权码。
-
client_secret: 客户端的密钥(确保请求来自合法客户端)。
-
-
授权服务器验证通过后,返回access_token(和可选的refresh_token)。
-
客户端用access_token调用资源服务器API(如获取用户个人信息)。
-
资源服务器验证Token有效性后返回请求的数据。
-
客户端显示用户信息或完成登录。
Oauth 2.0 和 OIDC 的关系
-
OAuth 2.0:仅授权,不提供用户身份认证。
-
OIDC:基于OAuth 2.0的扩展,添加id_token(JWT格式)明确用户身份信息。
- sub(用户ID)、iss(签发者)、aud(受众)、exp(过期时间)。
常见攻击与防御
攻击类型 | 防御措施 | 技术实现说明 |
---|---|---|
CSRF | 使用state 参数并验证回调来源 | 1. 生成随机state 存入Session2. 回调时校验 state 是否匹配 |
令牌泄露 | 短期令牌 + HTTPS + 范围限制 | 1. 设置expires_in≤3600 2. HSTS强制HTTPS 3. 按需申请 scope=read |
授权码拦截 | PKCE + 单次授权码 | 1. 客户端生成code_verifier 和code_challenge 2. 服务端验证哈希一致性 |
密码爆破 | 限流 + MFA | 1. 令牌桶算法限流 2. 集成Google Authenticator/SMS验证 |