微信掃碼登錄已成標配功能。本文完整梳理 PC 端「掃碼→授權→回調→綁定/註冊」全鏈路,涵蓋二維碼帶參生成、雙授權模式區分、access_token 換取、用戶信息獲取、UnionID 去重綁定等核心環節,附生產級代碼片段。
state 參數的授權二維碼redirect_uri 攜帶 code + statecode 換取 access_token → refresh_token → 用戶信息unionid(或 openid)查庫判斷:老用戶登錄 / 新用戶註冊綁定// 使用 phpqrcode 庫生成二維碼圖片流直接輸出
$state = generateUniqueState(); // 自定義業務標識,回調時原樣返回
$url = "https://open.weixin.qq.com/connect/oauth2/authorize?" . http_build_query([
'appid' => $appid,
'redirect_uri' => 'https://your.com/wcallback',
'response_type' => 'code',
'scope' => 'snsapi_userinfo', // 必須用 userinfo 才能拿 unionid
'state' => $state,
]);
QRcode::png($url, false, 'L', 5); // 直接輸出 PNG 圖片流
| 模式 | scope | 用戶感知 | 可獲取信息 | 適用場景 |
|---|---|---|---|---|
| 靜默授權 | snsapi_base | 無彈窗,直接跳轉 | 僅 openid | 已關注公眾號、僅需標識用戶 |
| 用戶信息授權 | snsapi_userinfo | 彈窗確認授權 | openid + unionid + 昵稱/頭像/性別/地區 | 開放平台綁定、需展示用戶資料 |
本文採用 snsapi_userinfo,確保能獲取 unionid 實現跨應用用戶唯一標識。
public function wcallbackAction() {
$code = $_GET['code'];
$state = $_GET['state']; // 驗證 state 防 CSRF
if (!$code) exit('授權失敗');
// 1. code 換 access_token
$tokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?" . http_build_query([
'appid' => $appid,
'secret' => $appsecret,
'code' => $code,
'grant_type' => 'authorization_code',
]);
$token = json_decode(httpGet($tokenUrl));
if (isset($token->errcode)) exit('Token錯誤:' . $token->errmsg);
// 2. 刷新 access_token(可選,延長有效期)
$refreshUrl = "https://api.weixin.qq.com/sns/oauth2/refresh_token?" . http_build_query([
'appid' => $appid,
'grant_type' => 'refresh_token',
'refresh_token' => $token->refresh_token,
]);
$access = json_decode(httpGet($refreshUrl));
// 3. 拉取用戶信息(含 unionid)
$infoUrl = "https://api.weixin.qq.com/sns/userinfo?" . http_build_query([
'access_token' => $access->access_token,
'openid' => $access->openid,
'lang' => 'zh_CN',
]);
$user = json_decode(httpGet($infoUrl));
if (isset($user->errcode)) exit('用戶信息錯誤:' . $user->errmsg);
// 4. 核心:unionid 去重綁定邏輯
$unionid = $user->unionid;
$existing = DB::getOne("SELECT user_id FROM user_bind WHERE type='weixin' AND unionid=?", [$unionid]);
if ($existing) {
// 老用戶:直接登錄,寫 session
loginByUserId($existing);
} else {
// 新用戶:註冊 + 綁定
$uid = registerUser(['nickname'=>$user->nickname, 'avatar'=>$user->headimgurl]);
bindWeixin($uid, $unionid, $access->openid);
loginByUserId($uid);
}
// 5. 通知 PC 端:WebSocket / 長輪詢 / 寫快取狀態
setLoginState($state, $uid); // PC 端輪詢該 state 即可感知
}
| 方案 | 實現複雜度 | 實時性 | 資源消耗 | 推薦指數 |
|---|---|---|---|---|
| AJAX 短輪詢 | 低 | 秒級 | 中 | ⭐⭐⭐ 簡單項目首選 |
| WebSocket 長連接 | 中 | 毫秒級 | 低 | ⭐⭐⭐⭐⭐ 高併發首選 |
| Server-Sent Events (SSE) | 低 | 毫秒級 | 低 | ⭐⭐⭐⭐ 輕量級最佳 |
// 授權成功後在微信內置瀏覽器關閉當前頁
WeixinJSBridge.call('closeWindow');
// 或跳轉到公眾號關注頁
location.href = 'weixin://profile/gh_xxxxxxxx';
掌握這套流程,即可實現從「掃碼」到「登錄」的閉環。建議將微信授權封裝為獨立 Service 類,配合事件驅動架構,支援多端(PC/H5/小程序)複用。