業務流程圖解
用戶訪問頁面
↓
引導至微信授權頁(scope=snsapi_userinfo)
↓
用戶點擊授權
↓
微信回調 redirect_uri?code=CODE&state=STATE
↓
後端用 code 換取 access_token + openid
↓
用 access_token + openid 拉取用戶詳情
↓
業務邏輯處理(綁定、登錄、註冊)
核心參數說明
| 參數 | 來源 | 說明 |
| appid | 公眾平台 | 公眾號唯一標識 |
| secret | 公眾平台 | 開發者密鑰,極度機密 |
| redirect_uri | 業務配置 | 授權後回調地址,需 URL 編碼 |
| scope | 固定值 | snsapi_base靜默獲取openid / snsapi_userinfo獲取用戶信息 |
| state | 自定義 | 防 CSRF、攜帶業務參數,原樣回傳 |
完整單文件實現
$user['openid'],
'nickname' => $user['nickname'],
'headimgurl' => $user['headimgurl'],
'sex' => $user['sex'], // 1男 2女 0未知
'city' => $user['city'],
'province' => $user['province'],
'country' => $user['country'],
'unionid' => $user['unionid'] ?? null, // 僅在綁定開放平台時返回
], JSON_UNESCAPED_UNICODE);
exit;
}
// ========== 工具函數 ==========
function httpRequest(string $url, array $postData = []): string {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false, // 生產環境建議開啟並配置 CA 憑證
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_TIMEOUT => 10,
CURLOPT_CONNECTTIMEOUT => 5,
]);
if ($postData) {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
}
$response = curl_exec($ch);
if ($response === false) {
throw new RuntimeException('cURL 錯誤: ' . curl_error($ch));
}
curl_close($ch);
return $response;
}
關鍵細節與避坑指南
1. 域名配置陷阱
- 公眾平台「開發配置」→「網頁授權域名」需填寫不帶協議和路徑的域名(如
domain.com)
- 回調頁域名必須與授權域名一致,支持子目錄
- 本地開發可用內網穿透(ngrok/frp)映射到公網域名
2. Scope 選擇策略
| Scope | 用戶感知 | 獲取信息 | 適用場景 |
| snsapi_base | 無感(靜默) | 僅 openid | 判斷關注、簡單標識用戶 |
| snsapi_userinfo | 彈窗授權 | 完整用戶信息 | 需頭像、暱稱、地區等業務 |
3. Access Token 刷新機制
// access_token 有效期 2 小時,過期需用 refresh_token 刷新
function refreshAccessToken(string $appid, string $refreshToken): array {
$url = "https://api.weixin.qq.com/sns/oauth2/refresh_token"
. "?appid={$appid}"
. "&grant_type=refresh_token"
. "&refresh_token={$refreshToken}";
return json_decode(httpRequest($url), true);
}
// 業務中建議:存儲 refresh_token 到數據庫,定時任務刷新
4. 狀態保持與 State 參數
// 生成授權 URL 時攜帶 state
$state = base64_encode(json_encode([
'from' => $_GET['from'] ?? 'index',
'csrf' => bin2hex(random_bytes(8)),
]));
$authUrl = "...&state={$state}#wechat_redirect";
// 回調驗證
$stateData = json_decode(base64_decode($_GET['state']), true);
if (!hash_equals($_SESSION['csrf_token'], $stateData['csrf'])) {
die('CSRF 攻擊檢測');
}
// 跳轉回原業務頁
header("Location: /{$stateData['from']}");
5. 多公眾號/開放平台 UnionID 打通
- 同一開放平台下的公眾號、小程序、APP 共享 UnionID
- 需在開放平台綁定公眾號,且用戶授權過該公眾號
- UnionID 是跨應用識別同一用戶的唯一鍵
生產環境架構建議
- 分層封裝:將 OAuth 邏輯封裝為 Service 類,Controller 僅調用
- 緩存 Token:access_token 存 Redis,key 為
wx:token:{appid},TTL 7000 秒
- 用戶表設計:存儲 openid、unionid、session_key、最新用戶信息、最後登錄時間
- 靜默授權降級:首次訪問嘗試 snsapi_base 獲取 openid,需詳細信息時再引導 snsapi_userinfo
- 錯誤碼處理:40029(code無效)、40163(code已被使用)、40003(openid不匹配) 等分類處理
- 上一篇文章: PHP 高性能郵件發送類:SMTP 協議原生實現、支援 SSL/TLS、附件、HTML 郵件
- 下一篇文章: Laravel 5.3 錯誤與日誌系統深度指南:配置、異常處理、自定義 Monolog
Copyright ©
程式碼之家 All Rights Reserved