OAuth 1.0a 三步驟流程
- 獲取 Request Token:應用向新浪申請臨時憑證。
- 用戶授權:用戶在新浪頁面登錄並授權,新浪重定向回應用帶
oauth_verifier。
- 換取 Access Token:應用攜帶 Request Token + Verifier 申請長期訪問憑證。
數據庫設計
CREATE TABLE `oauth_users` (
`id` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
`oauth_provider` VARCHAR(10) DEFAULT 'sina',
`oauth_uid` VARCHAR(64) NOT NULL, -- 新浪用戶數字 ID
`oauth_token` VARCHAR(255) NOT NULL, -- Access Token
`oauth_secret` VARCHAR(255) NOT NULL, -- Access Token Secret
`username` VARCHAR(100) DEFAULT '', -- 昵稱
UNIQUE KEY `uniq_provider_uid` (`oauth_provider`, `oauth_uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
步驟一:index.php 發起授權
getRequestToken(); // 獲取 oauth_token, oauth_token_secret
$_SESSION['oauth_request_token'] = $requestToken; // 保存供 callback 使用
$authorizeUrl = $oauth->getAuthorizeURL($requestToken['oauth_token'], false, CALLBACK_URL);
?>
使用新浪微博登錄
步驟二:callback.php 處理回調
getAccessToken($_GET['oauth_verifier']); // 關鍵步驟
// 獲取用戶信息
$user = $oauth->get('account/verify_credentials');
if (isset($user->error) || empty($user->id)) {
header('Location: index.php'); exit;
}
// 數據庫 upsert
$pdo = new PDO(DB_DSN, DB_USER, DB_PASS);
$stmt = $pdo->prepare("SELECT * FROM oauth_users WHERE oauth_provider='sina' AND oauth_uid=?");
$stmt->execute([$user->id]);
$row = $stmt->fetch();
if ($row) {
$pdo->prepare("UPDATE oauth_users SET oauth_token=?, oauth_secret=? WHERE id=?")
->execute([$accessToken['oauth_token'], $accessToken['oauth_token_secret'], $row['id']]);
$userId = $row['id'];
} else {
$pdo->prepare("INSERT INTO oauth_users (oauth_provider, oauth_uid, username, oauth_token, oauth_secret)
VALUES ('sina', ?, ?, ?, ?)")
->execute([$user->id, $user->screen_name, $accessToken['oauth_token'], $accessToken['oauth_token_secret']]);
$userId = $pdo->lastInsertId();
}
// 寫入 Session 登錄態
$_SESSION['user_id'] = $userId;
$_SESSION['username'] = $user->screen_name;
$_SESSION['oauth_token'] = $accessToken['oauth_token'];
$_SESSION['oauth_secret'] = $accessToken['oauth_token_secret'];
header('Location: update.php'); // 跳轉到發布/主頁
?>
關鍵安全細節
- oauth_verifier 單次使用:刷新 callback 頁面會報錯「Token used」,必須重新發起授權流程。
- State 參數防 CSRF:
$authorizeUrl = $oauth->getAuthorizeURL($token, false, CALLBACK_URL, $state);
Session 存 $state,Callback 驗證 $_GET['state'] === $_SESSION['state']。
- HTTPS 強制:生產環境所有 OAuth 交互必須走 HTTPS,防竊聽 Token/Secret。
- Token 加密存儲:資料庫中
oauth_token/secret 建議 AES 加密,密鑰配置在環境變量。
update.php 登錄態展示
OAuth 登錄成功
歡迎,=htmlspecialchars($_SESSION['username'])?>
發布微博 | 退出
WeiboOAuth 類核心方法簽名
class WeiboOAuth {
public function __construct($consumerKey, $consumerSecret,
$oauthToken = null, $oauthTokenSecret = null) { ... }
public function getRequestToken() { ... } // 返回 ['oauth_token'=>..., 'oauth_token_secret'=>...]
public function getAuthorizeURL($token, $signInWithSina, $callbackUrl, $state = null) { ... }
public function getAccessToken($verifier) { ... } // 返回 ['oauth_token'=>..., 'oauth_token_secret'=>..., 'user_id'=>...]
public function get($api, $params = []) { ... } // 簽名 GET 請求
public function post($api, $params = [], $files = []) { ... } // 簽名 POST 請求
}