Oauth2 授权码模式

流程图:


image.png

OAuth2.0 授权码模式(Authorization Code Flow)

一、核心定位

最安全、最常用的标准流程,适用于有后端服务的客户端(Web后端、APP后端、Java服务端),不适合纯前端单页应用(SPA)。
核心特点:

  1. 浏览器跳转授权,资源所有者登录授权;
  2. 前端只拿到临时授权码,密钥/ClientSecret保存在后端,不会暴露给浏览器;
  3. 用授权码换取 access_token + refresh_token

参与角色

  1. 资源所有者 User:用户(拥有账号数据)
  2. 客户端 Client:你的Java业务系统(第三方应用)
  3. 授权服务器 AuthServer:登录、颁发token(如微信开放平台、GitHub、自研OAuth服务)
  4. 资源服务器 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:用户登录并授权

  1. 未登录:跳登录页输入账号密码;
  2. 已登录:弹出授权弹窗:是否允许你的应用获取XX信息;
  3. 用户同意 → 进入步骤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。

四、为什么授权码模式最安全?对比其他模式

  1. 隐藏client_secret
    code交换token逻辑在Java服务端执行,密钥不暴露浏览器;
    简化模式(implicit)直接前端返回access_token,密钥无保护,不安全。
  2. 一次性code
    授权码只能使用一次,截获也无法重复换token;
  3. 支持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_coderefresh_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开发重点注意)

  1. 不校验state → CSRF攻击,攻击者伪造授权;
  2. redirect_uri 模糊匹配,未严格全路径校验 → 跳转钓鱼站点窃取code;
  3. client_secret 存前端/浏览器、本地缓存 → 密钥泄露;
  4. access_token 通过URL传递(日志泄露),必须放Header Authorization;
  5. 授权码未一次性销毁,重复使用未拦截;
  6. 不校验token签名、过期时间,直接信任access_token。
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容