通過 OAuth 進行 Twitter 身份驗證

八月 29th, 2010 · by avenger · 技術 · 2,312 views

本年 8 月 16 日起,Twitter 官方不再支持基本身份認證協議(basic authentication protocol)。這意味着開發者唯一可以訪問 Twitter 的方法是利用 Twitter 的第三方應用。在本篇教程中,我會講解如何通過 PHP 來使用 Twitter 官方的一鍵登錄系統。

作者:Rafael Soto
原文鏈接:http://net.tutsplus.com/tutorials/php/how-to-authenticate-users-with-twitter-oauth/

本文中用到的類庫 twitteroauth 下載

第一步:創建應用

我們首先需要申請一個新的 Twitter 應用。

  • 點擊這裏,在 dev.twitter.com 打開註冊新應用的表單
  • 根據你的需要添加表單中的各項內容,確認在應用類型(Application Type)那裏要選擇“瀏覽器(Browser)”,並設置一個回調地址(Callback URL),例如像 http://localhost.com/twitter_login.php 這樣的地址,(http://localhost/ 這樣的地址可不行,因爲不包含域名信息);
  • 最後選擇讀和寫(Read & Write),並填寫驗證碼,點擊註冊應用(Register Application)按鈕來完成申請。

如果沒出現錯誤,完成以上步驟後,你應該能看到如下畫面:

注意上圖的紅框,等一下我們將用到上圖中的 Consumer key 和 Consumer secret 信息。

網上已經有了不少現成的 Twitter 認證的類庫,可以簡化我們的工作。在 PHP 裏面我推薦 twitteroauth ,是比較好用的一個,如果你使用其它開發語言,可以在這裏找適合你的類庫

請在下載到的壓縮包中找到名爲 twitteroauth 的目錄,將其部署到你的應用程序根目錄下。

在我們開始編碼前,我們還需要一張數據庫來保存用戶信息,下面是一個基本的 Mysql 的例子:

1
2
3
4
5
6
7
8
9
CREATE TABLE `users` (
    `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `oauth_provider` varchar(10),
    `oauth_uid` text,
    `oauth_token` text,
    `oauth_secret` text,
    `username` text,
    PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;

注意 oauth_token 和 oauth_secret 這兩個字段。TwitterOAuth 認證需要 token 和 token_secret 兩個參數來完成認證,所以我們需要預留兩個字段來記錄他們。

第二步:註冊用戶

我們需要依次完成以下工作:

  • Twitter 發起認證申請
  • 註冊/或者登錄,如果用戶已經有帳號的情況下
  • 將相關數據保存在 Session 中

申請認證

基於 OAuth 的認證流程從生成一個網址開始。用戶被重定向到該網址要求認證,認證通過後,會重定向到我們的應用服務器,並會將兩個認證後的參數通過 URL 方式傳回。

準備好剛纔下載的類庫,初始化 Session,讓我們開始吧:

1
2
require("twitteroauth/twitteroauth.php");
session_start();

創建一個新的 TwitterOAuth 實例,傳入我們在第一步申請應用時獲取到的 consumer key 和 consumer secret。接下來我們準備發出認證請求,保存認證信息到 Session 中,然後重定向到 Twitter 網站進行認證。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 創建 TwitterOAuth 對象實例
$twitteroauth = new TwitterOAuth('YOUR_CONSUMER_KEY', 'YOUR_CONSUMER_SECRET');
// Requesting authentication tokens, the parameter is the URL we will be redirected to
$request_token = $twitteroauth->getRequestToken('http://localhost.com/twitter_oauth.php');
 
// 保存到 session 中
$_SESSION['oauth_token'] = $request_token['oauth_token'];
$_SESSION['oauth_token_secret'] = $request_token['oauth_token_secret'];
 
// 如果沒有錯誤發生
if($twitteroauth->http_code==200){
    // Let's generate the URL and redirect
    $url = $twitteroauth->getAuthorizeURL($request_token['oauth_token']);
    header('Location: '. $url);
} else {
    // 發生錯誤,你可以做一些更友好的處理
    die('Something wrong happened.');
}

將代碼保存爲 twitter_login.php, 然後訪問 http://localhost.com/twitter_login.php 進行測試,如果一切 OK 的話,你應該會被重定向到 twitter.com,你將看到如下畫面:

點擊允許(allow)按鈕,你將被重定向到 http://localhost.com/twitter_oauth.php — 這是我們在上段代碼裏設置過的,不過我們還沒創建這個文件,所以現在代碼會拋出一個錯誤。讓我們建立這個文件,記得要先加入包含類庫和初始化 Session 的代碼,就像我們第一個例子裏那樣。

接下來,我們還需要在這個文件中完成以下三件事:

  • 驗證 URL 中的數據
  • 驗證 Session 中的 token 數據
  • 驗證 Session 中的 secret 數據

所以,首先要進行數據合法性的判斷:

1
2
3
4
5
6
if(!empty($_GET['oauth_verifier']) && !empty($_SESSION['oauth_token']) && !empty($_SESSION['oauth_token_secret'])){
    // 數據合法,繼續
} else {
    // 數據不完整,轉到上一步
    header('Location: twitter_login.php');
}

如果所有數據庫都是合法的,我們需要創建一個新的 TwitterOAuth 對象實例,跟之前不同的是,我們要把獲取到的 token 數據做爲參數傳入對象。之後,我們應該可以獲取到一個 access token,這個獲取到的數據應該是一個數組,這個 access token 是我們唯一需要保存起來的數據,先來做一個簡單的測試吧:

1
2
3
4
5
6
7
8
9
10
// TwitterOAuth 對象實例,注意新加入的兩個參數
$twitteroauth = new TwitterOAuth('YOUR_CONSUMER_KEY', 'YOUR_CONSUMER_SECRET', $_SESSION['oauth_token'], $_SESSION['oauth_token_secret']);
// 獲取 access token
$access_token = $twitteroauth->getAccessToken($_GET['oauth_verifier']);
// 將獲取到的 access token 保存到 Session 中
$_SESSION['access_token'] = $access_token;
// 獲取用戶信息
$user_info = $twitteroauth->get('account/verify_credentials');
// 打印用戶信息
print_r($user_info);

一切正常的話,上面的代碼會輸出用戶的資料。你可以通過 $user_info->id 來獲得用戶的 ID,通過 $user_info->screen_name 來獲取用戶名,等等,其它的信息也可以通過同樣的方式獲取。

需要重點指出的是,oauth_verifier 這個傳回來的參數不能被重用,如果上面的代碼已經正確輸出了用戶信息,你可以試着重新刷新頁面,應該會看到頁面會拋出一個錯誤信息,因爲 oauth_verifier 已經被我們用過一次了。要再次使用,需要到 twitter_login.php 頁面重新發起一個認證請求。

用戶註冊

獲得了用戶信息後,現在我們要開始把用戶信息註冊到我們自己的數據庫中,當然前提是用戶沒有在本地數據庫註冊過。首先要連接數據庫,代碼如下:

1
2
mysql_connect('localhost', 'YOUR_USERNAME', 'YOUR_PASSWORD');
mysql_select_db('YOUR_DATABASE');

上面代碼中的數據庫鏈接信息要改成你自己的。如果用戶已經存在於我們的數據庫中,我們需要更新用戶的 tokens 字段,因爲這說明 Twitter 生成了新的 tokens,數據庫中的 tokens 已經過期了。如果用戶不存在,我們需要新加一條記錄,並將相關的數據保存在 Session中,最後重定向回 twitter_update.php 頁面。相關代碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
if(isset($user_info->error)){
    // Something's wrong, go back to square 1
    header('Location: twitter_login.php');
} else {
    // Let's find the user by its ID
    $query = mysql_query("SELECT * FROM users WHERE oauth_provider = 'twitter' AND oauth_uid = ". $user_info->id);
    $result = mysql_fetch_array($query);
 
    // If not, let's add it to the database
    if(empty($result)){
        $query = mysql_query("INSERT INTO users (oauth_provider, oauth_uid, username, oauth_token, oauth_secret) VALUES ('twitter', {$user_info->id}, '{$user_info->screen_name}', '{$access_token['oauth_token']}', '{$access_token['oauth_token_secret']}')");
        $query = mysql_query("SELECT * FROM users WHERE id = " . mysql_insert_id());
        $result = mysql_fetch_array($query);
    } else {
        // Update the tokens
        $query = mysql_query("UPDATE users SET oauth_token = '{$access_token['oauth_token']}', oauth_secret = '{$access_token['oauth_token_secret']}' WHERE oauth_provider = 'twitter' AND oauth_uid = {$user_info->id}");
    }
 
    $_SESSION['id'] = $result['id'];
    $_SESSION['username'] = $result['username'];
    $_SESSION['oauth_uid'] = $result['oauth_uid'];
    $_SESSION['oauth_provider'] = $result['oauth_provider'];
    $_SESSION['oauth_token'] = $result['oauth_token'];
    $_SESSION['oauth_secret'] = $result['oauth_secret'];
 
    header('Location: twitter_update.php');
}

需要注意的是,上面代碼中的 SQL 沒有經過驗證,你在實際使用的時候可能要經過修改。連接數據庫前,我們需要先驗證一下用戶是否已經登錄:

1
2
3
4
if(!empty($_SESSION['username'])){
    // User is logged in, redirect
    header('Location: twitter_update.php');
}

有了用戶名,我們就可以展示一條個性的歡迎信息了:

1
<h2>Hello <?=(!empty($_SESSION['username']) ? '@' . $_SESSION['username'] : 'Guest'); ?></h2>

Let’s get to the fun side: updating, following and reading.

第三步:獲取用戶狀態

Twitter 官方 API 提供了二十餘種資源供開發者使用,例如:timeline, tweets, users, trends, lists, direct messages, 等等。 每一種資源都有對應一堆的方法可供調用的,具體的用法和介紹可以參見官方文檔。我們這裏只實現最簡單的,其它的你可以舉一反三。

跟前兩步一樣,代碼開始前你要先創建對象實例,並初始化 Session。

1
2
3
if(!empty($_SESSION['username'])){
    $twitteroauth = new TwitterOAuth('YOUR_CONSUMER_KEY', 'YOUR_CONSUMER_SECRET', $_SESSION['oauth_token'], $_SESSION['oauth_secret']);
}

我們來試着獲取用戶的 timeline 數據,手冊告訴我們,資源的路徑是 statuses/home_timeline,手冊上的版本號和格式參數我們不需要關心,類庫已經幫我們自己完成了。

1
2
$home_timeline = $twitteroauth->get('statuses/home_timeline');
print_r($home_timeline);

用上面的代碼,你應該可以獲取到正確的數據了。如果你願意,可以用一個 foreach 來循環展示具體的條目。手冊上關於 timeline 資源的說明中,還有一些參數可以供選擇的,例如每次獲取的條數。上面代碼的 get 方法有一個可選參數,你可以根據需要傳入相應的值。如果想獲取最新的 40 條數據,只需要使用下面的代碼:

1
$home_timeline = $twitteroauth->get('statuses/home_timeline', array('count' => 40));

當然,你可以獲取任何人的公開的 timeline 數據。使用 statues/user_timeline 資源即可,需要傳入要獲取用戶的用戶 ID 或用戶名。例如想獲取 @nettuts 的 timeline 數據,你需要下面的代碼:

1
$nettuts_timeline = $twitteroauth->get('statuses/user_timeline', array('screen_name' => 'nettuts'));

看到了吧,只要授權通過,獲取這些 timeline 數據,只不過是小意思。

第四步:好友關係

通過好友關係,你可以檢查某個用戶是否是另一個用戶的關注者(Follows),當然也可以關注、或者取消關注指定的用戶,下面的代碼片斷用來檢查你是否是筆者的關注者,如果不是的話,則會自動關注筆者。

首先,讓我們先來看一下開發者手冊上關於 friendships/existsfriendships/create 的這部分說明。注意到了嗎?friendships/create 的調用方法是 POST,跟我們前面用的 GET 有些不同。當然,我們用的類庫中已經包含了一個叫 post() 的方法,使用起來跟之前的 get() 差不多,唯一不同的地方在於 get() 是用來獲取數據的,而 post() 一般用來更新、創建和刪除數據。

friendships/exists 需要傳入兩個參數:用戶A 和 用戶B。friendships/create 則只需要一個參數:用戶名(screen_name)或 用戶ID( user_id)。

1
2
3
4
5
$follows_faelazo = $twitteroauth->get('friendships/exists', array('user_a' => $_SESSION['username'], 'user_b' => 'faelazo'));
if(!$follows_faelazo){
    echo 'You are NOT following @faelazo!';
    $twitteroauth->post('friendships/create', array('screen_name' => 'faelazo'));
}

同樣,你可以用類似的代碼來取消關注某個用戶,只需簡單的把 create 替換爲 destory:

1
2
3
4
5
$follows_faelazo = $twitteroauth->get('friendships/exists', array('user_a' => $_SESSION['username'], 'user_b' => 'faelazo'));
if($follows_faelazo){
    echo 'You are following @faelazo! Proceed to unfollow...';
    $twitteroauth->post('friendships/destroy', array('screen_name' => 'faelazo'));
}

第五步:更新

This is probably the most interesting section, since it’s Twitter’s core: posting an update, as you might have imagined, is pretty straightforward. The path is statuses/update, the method is POST (since we are not reading), and the one required argument is status.

1
$twitteroauth->post('statuses/update', array('status' => 'Hello Nettuts+'));

如果上面的代碼執行成功的,到你的 Twitter 頁面看下,你應該會看到類似的畫面:

讓我們試着轉發 @Nettut 的這條 twitterthe HTML 5 Competition,這條記錄的 ID 是 19706871538,手冊告訴我們,轉發需要調用的資源路徑是: statuses/retweet/:id, :id 即是我們要轉發的消息 ID,方法爲 POST,此方法不需要其它附加的參數。

$twitteroauth->post('statuses/retweet/19706871538');

要刪除某條消息,我們需要傳入要刪除的消息 ID,就像轉發的操作那樣,假設消息的 ID 爲 123456789,刪除這條消息的代碼如下:

1
$twitteroauth->post('statuses/destroy/123456789');

當然,上面刪除的代碼有個前提,只會刪除有經過我們授權的用戶消息。

小結

Twitter 的 API 很簡單,很容易讓人理解,甚至比 FaceBook 的文檔都容易得多。遺憾的是認證的過程需要繞一些彎子。

有一點需要特別提醒的是,如果你的應用得到了用戶的授權(你的應用有了讀寫權限),你基本上就相當於控制了這個用戶帳戶使用權。請小心使用你的權利,少做一些未經過用戶授權的事,這會給你製造不少麻煩。

Twitter 很快就會取締基本身份驗證模式(Basic Authentication),OAuth 是最終的解決方案。你現在就可以試着將本文學到的知識應用到你的網站上。讓用戶不用註冊,就可以用世界上最流行的網站帳號直接登錄,不也是一件很酷的事情嗎?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章