使用cookie做用戶登錄的過程詳解

不管是遊戲,還是網站,最基本的功能,就是用戶註冊登錄。 

或許,我們做過多次用戶的登陸註冊的功能,但我們是否想過,爲什麼要實現用戶的登錄。用戶怎樣做纔算登錄成功。

對用戶而言,登錄後,就有了他的一片“天地”,例如,登錄CSDN後,就可以管理自己的博客,否則,你沒有權利管理。關於是否登錄成功的問題,在用戶看來,如果用戶名和密碼輸入成功,就算登入成功,否則,登錄不成功。

但這一切,在程序中是怎樣實現的呢?在程序中,怎樣判定這個用戶處於登錄狀態,怎樣判斷用戶是否有權利訪問某個URL,例如管理自己的博客。

爲了搞清楚上面的問題,需要我們瞭解的一個知識點是,HTTP協議實際上是無狀態的,非持久連接。也就是說,你第二次通過某個瀏覽器訪問WEB應用,他其實不知道你已經來過一次了。

這裏,有一個問題就是,我們的需求是需要知道用戶“是否登錄”了,即當這個用戶登錄後,第二次訪問的服務器的時候,服務器需要知道請求是來自同一個用戶,可是,由於HTTP協議是無狀態的,服務器無法知道兩次訪問是不是來自同一個人。

這裏就使用到COOKIE技術了,使用COOKIE可以解決以上問題,讓服務器知道用戶是否登錄。

 cookie是什麼?
 cookie是一個文本文件,保存在客戶端硬盤中(如果設置了cookie的過期時間),或者在用戶的瀏覽器內存中(如果cookie是臨時的)。這個文件對用戶來說,是透明的,你可以通過瀏覽器工具來查看當前的cookie,可能不止一個。

cookie是什麼時候被保存在瀏覽器中的?

這個問題很重要,瀏覽器的cookie值不會憑空產生。它是服務器端通知客戶端的產生的。如果用戶瀏覽器支持COOKIE,使用下面一段代碼就可以創建COOKIE。

setcookie($name, $value, $expire, $path, $domain, $secure)

$path: 千萬不要把這個路徑理解爲cookie的保存路徑,如果不設置,則路徑爲目錄,服務器中的所有腳本都可以訪問到,The path on the server in which the cookie will be available on. If set to '/', the cookie will be available within the entire domain

$domain: 表示這個cookie所屬的域,cookie是不能跨域訪問的。

例如:

setcookie('xxx', 'yyyyyyyyyyyyy');

當用戶第一次訪問這段程序的時候,setcookie函數會生成cookie文件,並保存在瀏覽器的response Header,注意,這個時候,如果訪問服務器中的全局數據$_COOKIE,會發現這個數組爲空。此時,客戶端還沒有把cookie信息傳到服務器端。

瀏覽器還沒有保存這個cookie



當第二次訪問這個頁面的時候,這個時候,瀏覽器會自動把cookie信息傳到服務器端(如果這個cookie沒有過期的話)。這樣,服務器才保存了這個cookie。



服務器中,如果獲取到這個cookie值?

在PHP中,任何從客戶端傳過來的cookie都可以保存在$_COOKIE這樣的全局函數中。在服務器端,可以通過這個數組來訪問cookie的信息。記住,第一次讀取它的信息的時候,並不會生效。原因就是我上面說的。


那麼我們怎麼利用cookie實現用戶登陸呢?

流程圖:



  使用COOKIE保存用戶的TOKEN值。這樣,服務器會讀取保存在$_COOKIE數組裏面的信息判斷用戶是否登陸。


  代碼展示:

登陸時,當用戶輸入正確的用戶名和密碼後,需要調用下面的代碼:

    /**
     * 刷新 userToken
     *
     * @param int $uid
     * @param string $userToken
     * @param int $expires
     * @throws Core_Exception_Logic
     * @return void
     */
    private function _refreshUserToken($uid, $userToken = null, $expires = null)
    {
        // 生成新的TOKEN值
        if (! $userToken) {
            $userToken = self::genUserToken($uid);
        }

        // 更新玩家的TOKEN
        if (! Dao('Share_UserIndex')->updateUserToken($uid, $userToken)) {
            throws(_('登陸失敗,請稍候再試'));
        }

        // 設置用戶憑證到 cookie
        $this->_setUserCookie($userToken, $expires);
    }

爲什麼登陸成功後,都要更新用戶的TOKEN值呢?

防止,如果用戶A的token值一直都更新,被用戶B竊取,這樣,用戶B僞造COOKIE,如使用瀏覽器直接添加一個COOKIE,這樣可以直接登陸用戶A的賬號,繞過了用戶名和密碼的驗證。

第二,就是保證一個賬號只能是一個用戶登陸。

在控制器的入口處檢查用戶是否登陸:

abstract class Controller_Abstract extends Core_Controller_Web
{
    /**
     * 構造函數
     */
    public function init()
    {
        // 獲取當前已登錄用戶 userIndex
        if (! $this->_userIndex = $this->_auth->getUserByToken()) {
            $this->_checkAuth && $this->vRedirect('/auth/login');
        }

        // 如果已登錄
        if ($this->_userIndex) {

            // 實例化一個玩家實例
            $this->_user = new Model_User($this->_uid);
        }

    }
}


其中 getUserByToken()函數就是根據保存在COOKIE裏面的token值來查找用戶,如果查找到,說明這個用戶已經登陸,否則未登陸。

    /**
     * 獲取當前已登錄用戶信息
     *
     * @return false/array
     */
    public function getUserByToken()
    {
        // 獲取用戶的標識符
        if (! $userToken = F('Cookie')->get(self::$cookieName)) {
            return false;
        }

        // 根據相應的userToken 查找用戶
        return Dao('Share_UserIndex')->getUserByToken($userToken);
    }


注意一點:在登陸的時候,除了使用cookie保存以外,還可以使用session,但是,爲什麼我們還少使用session做登陸註冊呢,因爲session的值是保存在服務器中的,在一些大型的應用中,服務器可能不止一臺,所以,無法知道,用戶註冊的session保存在哪臺服務器上。

但是,記住一點就是,session可以保存在memcached中。這裏需要修改PHP.INI配置文件。

發佈了41 篇原創文章 · 獲贊 14 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章