应使用 league/oauth2-client 库而非手动实现 OAuth2 流程,因其可避免 invalid_redirect_uri、invalid_grant 及 CSRF 等 90% 的线上故障;授权 URL 必须包含 response_type=code、client_id、redirect_uri、state 四个参数,且 redirect_uri 需与注册值完全一致(含协议、端口、路径及末尾斜杠),state 须由服务端用 random_bytes(16)+bin2hex() 生成并存入 $_SESSION;回调页须立即校验并销毁 state;换 token 时 POST 请求需满足:Content-Type 为 application/x-www-form-urlencoded、带正确的 Authorization: Basic 头、body 用 http_build_query 拼装且 redirect_uri 严格一致;资源接口调用须用 Authorization: Bearer {token} 格式;access_token 应后端保管或存 HttpOnly Cookie;微信 access_token 无 expires_in,需自行计算过期时间;务必保证 redirect_uri 协议、端口等全量一致,否则静默失败。

一、用 league/oauth2-client 替代手写 curl
别自己拼 URL、自己发 POST 换 token——90% 的 invalid_grant、invalid_redirect_uri、CSRF 漏洞都源于此。直接装官方推荐库:
composer require league/oauth2-client
它已适配 PHP 8.5,自动处理 state 生成/校验、redirect_uri 编码、token 请求头(Authorization: Basic)、响应解析等细节。微信、GitHub、Google 等平台都有现成 Provider(如 League\OAuth2\Client\Provider\Github)。
二、回调地址必须一字不差
这是最常踩的坑。注册应用时填的 redirect_uri 和代码里传入的,必须完全一致:
- 协议相同(
https://,不用http) - 域名+端口精确(
example.com≠www.example.com;:443隐含时不写,但:8443必须带上) - 路径带或不带结尾斜杠要统一(
/auth/wechat/callback≠/auth/wechat/callback/) - 中文或特殊字符必须
urlencode()(如https://example.com/回调.php→https%3A%2F%2Fexample.com%2F%E5%9B%9E%E8%B0%83.php)
三、state 必须服务端生成并销毁
防 CSRF 的强制关卡,不能跳过:
立即学习“PHP免费学习笔记(深入)”;
- 跳转前生成:
$_SESSION['oauth2state'] = bin2hex(random_bytes(16)); - 构造授权 URL 时带上:
'state' => $_SESSION['oauth2state'] - 回调页第一行就校验:
if (!isset($_GET['state']) || $_GET['state'] !== $_SESSION['oauth2state']) { exit('Invalid state'); } - 校验通过后立刻清除:
unset($_SESSION['oauth2state']);
四、access_token 别让前端碰
token 是敏感凭证,PHP 8.5 下更应严守边界:
- 绝不存 localStorage 或 sessionStorage
- 后端用 session 或加密后存 HttpOnly Cookie(推荐)
- 调用用户信息接口时,用
Authorization: Bearer {token}请求头,不要放 query 或 body - 微信等平台返回的 access_token 无
expires_in字段?自己记时间戳 + 2 小时过期,别依赖响应字段



















