流程图:

image.png
OAuth2.0 授权码模式(Authorization Code Flow)
一、核心定位
最安全、最常用的标准流程,适用于有后端服务的客户端(Web后端、APP后端、Java服务端),不适合纯前端单页应用(SPA)。
核心特点:
- 浏览器跳转授权,资源所有者登录授权;
- 前端只拿到临时授权码,密钥/ClientSecret保存在后端,不会暴露给浏览器;
- 用授权码换取
access_token+refresh_token。
参与角色
- 资源所有者 User:用户(拥有账号数据)
- 客户端 Client:你的Java业务系统(第三方应用)
- 授权服务器 AuthServer:登录、颁发token(如微信开放平台、GitHub、自研OAuth服务)
- 资源服务器 ResourceServer:存放用户数据,校验access_token
二、完整流程(6步)
前置配置(Java开发必做)
客户端提前在授权平台注册,拿到:
-
client_id:客户端标识(公开) -
client_secret:客户端密钥(后端保存,严禁前端泄露) -
redirect_uri:回调地址(必须提前配置,防劫持) - 授权范围
scope:需要哪些用户信息(user_info、email等)
步骤1:客户端跳转授权页面(前端浏览器发起)
浏览器GET请求授权服务器 /authorize 接口
GET https://auth-server.com/oauth2/authorize
?response_type=code
&client_id=CLIENT_ID
&redirect_uri=https://your-java-server/callback
&scope=user_info
&state=随机字符串(防CSRF攻击)
参数说明:
-
response_type=code:指定使用授权码模式 -
state:前端生成随机串,回调时原样带回,校验防跨站伪造
步骤2:用户登录并授权
- 未登录:跳登录页输入账号密码;
- 已登录:弹出授权弹窗:是否允许你的应用获取XX信息;
- 用户同意 → 进入步骤3;拒绝 → 回调携带错误参数。
步骤3:授权服务器重定向回调,返回授权码
浏览器自动跳转你的 redirect_uri,携带临时授权码 code
GET https://your-java-server/callback
?code=AUTH_CODE_123456
&state=之前下发的随机串
-
code:短期有效(通常5分钟内一次性使用) - Java后端首先校验
state和本地缓存是否一致,拦截CSRF攻击
步骤4:Java后端拿code换令牌(关键!全程后端HTTP调用,不经过浏览器)
后端POST请求授权服务器 /token 接口,带上client_secret
POST https://auth-server.com/oauth2/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&client_id=CLIENT_ID
&client_secret=CLIENT_SECRET
&redirect_uri=https://your-java-server/callback
&code=AUTH_CODE_123456
步骤5:授权服务器返回令牌组
成功返回JSON:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer",
"expires_in": 7200, // access_token有效期,单位秒(2小时)
"refresh_token": "xxx", // 长效刷新令牌,用于续期
"scope": "user_info"
}
-
access_token:访问资源接口凭证,短期有效; -
refresh_token:后端保存,access_token过期后无需用户重新授权,直接换新token。
步骤6:Java后端携带access_token请求资源服务器拿用户数据
GET https://resource-server.com/api/user/info
Authorization: Bearer {access_token}
拿到用户唯一标识、昵称、头像等业务数据,完成登录。
三、刷新Token流程(Java后端实现)
access_token过期后,用refresh_token换取新access_token,不用重新跳转授权:
POST /oauth2/token
grant_type=refresh_token
client_id=xxx
client_secret=xxx
refresh_token=xxx
返回新的access_token,部分服务会同时返回新refresh_token。
四、为什么授权码模式最安全?对比其他模式
-
隐藏client_secret
code交换token逻辑在Java服务端执行,密钥不暴露浏览器;
简化模式(implicit)直接前端返回access_token,密钥无保护,不安全。 -
一次性code
授权码只能使用一次,截获也无法重复换token; -
支持refresh_token
可长期维持登录态,适合后台系统、APP服务端。
五、Java开发落地(Spring Security OAuth2 / Spring Authorization Server)
1. 自研授权服务(Spring Authorization Server)
核心配置开启授权码模式:
authorizationEndpoint -> authorizationEndpoint
.authorizationRequestConverter(customConverter)
.consentPage("/oauth2/consent")
tokenEndpoint -> tokenEndpoint
.accessTokenResponseHandler(customResponse)
支持 authorization_code、refresh_token 两种grant_type。
2. 客户端(业务Java服务)对接第三方OAuth(Gitee/微信/企业微信)
使用 Spring Security OAuth2 Client,自动完成跳转、回调、换token逻辑:
spring:
security:
oauth2:
client:
registration:
gitee:
client-id: xxx
client-secret: xxx
redirect-uri: "{baseUrl}/login/oauth2/code/gitee"
authorization-grant-type: authorization_code
provider:
gitee:
authorization-uri: https://gitee.com/oauth/authorize
token-uri: https://gitee.com/oauth/token
user-info-uri: https://gitee.com/api/v5/user
六、常见安全坑(Java开发重点注意)
- 不校验state → CSRF攻击,攻击者伪造授权;
- redirect_uri 模糊匹配,未严格全路径校验 → 跳转钓鱼站点窃取code;
-
client_secret存前端/浏览器、本地缓存 → 密钥泄露; - access_token 通过URL传递(日志泄露),必须放Header Authorization;
- 授权码未一次性销毁,重复使用未拦截;
- 不校验token签名、过期时间,直接信任access_token。