1. 程式人生 > >使用COOKIE實現登錄 VS 使用SESSION實現登錄

使用COOKIE實現登錄 VS 使用SESSION實現登錄

提交 登錄界面 兩個 必須 linux系統 加密方法 跳轉 函數 coo

註:本文使用的代碼基於PHP,其他語言邏輯同理。

一:使用COOKIE實現登錄驗證

使用cookie實現登錄的方式,主要通過一些單向的加密信息進行驗證。比如admin用戶登錄了之後,服務端生成一個cookie值:admin_1533006028_ bbf2c2b1ec5cfb62d0a30438d8d0305c ,這個cookie值包含用戶名,cookie到期時間和一個信息簽名。簽名的信息為 ”用戶名_用戶密碼_cookie到期時間_鹽” 比如:md5(”admin_1533006028_123456_salt123”)。這樣用戶每次訪問,只要獲取到這個cookie值,然後驗證cookie到期時間和簽名。就可以判斷該用戶是否已登錄。

首先看看下面cookie登錄的實例代碼:

<?php
class Login { //登錄 public function login($account,$password) { $lifetime = time()+3600; $model = new Model(); $pwd = md5($password); $userInfo = $model->db->getOne(array(‘username’=>$username,’password’=>$pwd);
if($userInfo){ $cookie =$this->user2cookie($userInfo, $lifetime); setcookie(‘account‘, $cookie, $lifetime); return true; }else{ return false; } } //驗證登錄 public static function isLogin() { $cookie = $_COOKIE[‘account‘];
$re = $this->cookie2user($cookie); return $re; } //根據cookie判斷一個用戶是否合法的登錄用戶 public function cookie2user($cookie) { if(empty($cookie)) return false; list($username,$lifetime,$token) = explode(‘_‘,$cookie); //cookie過期或者cookie1分鐘內過期 if($lifetime < (time()+60)) return false; $model = new Model(); //獲取緩存中的用戶信息 $userInfo = $model->redis->get($username); if(!$userInfo){ $userInfo = $model->db->getOne(array(‘username’=>$username)); }else{ $userInfo = parse_url($userInfo); } if(!$userInfo){ return false; } //驗證token值 $str = $username.$userInfo[‘password‘].$lifetime.$userInfo[‘salt’]; if($token !== md5($str)) return false; $val = http_build_query($userInfo , ‘‘ , ‘&‘); //將用戶信息設置到緩存中,鍵值生命周期為1小時。 $model->redis->set($username,$val,3600); return true; } //生成驗證用戶登錄的cookie值 public function user2cookie($user,$lifetime) { $str = $user[‘username‘].$user[‘password‘].$lifetime.$user[‘salt’]; $token = md5($str); $re = $user[‘username‘].‘_‘.$lifetime.‘_‘.$token; return $re; } } ?>

cookie的登錄流程: 首先通過Login() 函數驗證用戶提交的用戶名和密碼,如果驗證通過則將相關信息寫入cookie, 後面使用isLogin() 函數對用戶的每次訪問進行驗證,驗證的方式也是通過該用戶的cookie。驗證通過則說明該用戶已經登錄,否則說明該用戶沒有登錄。跳轉到登錄頁面。

這裏重點講下Login類的兩個關鍵函數cookie2user和user2cookie:

1、 cookie2user根據cookie判斷一個用戶是否合法的登錄用戶,即用戶每次訪問,都會通過isLogin函數驗證該用戶是否已經登錄。驗證方式就是獲取到用戶此次訪問的cookie值,然後將驗證cookie值裏的token(簽名信息)值。驗證通過,說明該用戶是已經登錄的,否則就是為登錄或者不存在該用戶。

2、 user2cookie用於生成驗證用戶登錄的cookie值。如前文所述,該cookie值包含用戶名、cookie生存時間和token值。這裏關鍵就是這個token值的生成方式,要註意判斷登錄的時候生成token值的方式要與此函數生成token值的方式一致。比如這裏是將用戶名,用戶密碼,cookie生存時間和鹽進行連接並取md5值。當然加密方法也可以不用md5,也可以使用sha1等。

二、使用SESSION實現登錄驗證

由於session的信息是保留在服務端的,所以用戶登錄戶的信息保存在服務,所以無需像cookie登錄的那樣將信息進行單向加密。

session登錄的示例代碼:

<?php

class Login
{
   //登錄
   public function  login($account,$password)
   {
        $model = new Model();
        $pwd = md5($password);
        $userInfo = $model->db->getOne(array(‘username’=>$username,’password’=>$pwd);
        if($userInfo){
           $_SESSION[‘account’] = $userInfo;
           return true;
        }else{
            return false;
        }
    }

 
    //驗證登錄
    public static function isLogin()
    {
         if(isset($_SESSION[‘account‘])){
                return true;
         }else{
                return false;
         }
    }

}

?>    

session的登錄流程:首先用戶提交的用戶名和密碼提交到Login() 方法進行驗證,如果驗證通過則將信息寫入session,後面每次訪問都會去取該用戶的session信息。如果不存在該用戶的SESSION信息,則說明該用戶還沒有登錄,跳轉到登錄頁面。已經登錄了的用戶每次訪問,都會通過isLogin() 函數進行驗證。驗證不通過說明登錄過期或者沒有登錄,則跳轉到登錄頁面。

兩種方式都是通過isLogin() 方法來驗證用戶是否已經登陸的了。該方法一般在程序的入口處進行Login::isLogin() 調用,從而對所有的訪問進行驗證。

三、兩種方式的異同點

除了上文已經簡述的之外,這裏先介紹下PHP裏面處理SESSION的機制。

PHP在調用seesion_start() 函數之後會生成一個字符串(一般是某些不重復的哈希值)。這個字符串就是session_id,當然這個值也可以自行調用函數session_id(‘指定的session_id 值’)進行構建,需要註意的是,session_id()函數必須在session_start() 函數之前先調用。只有調用了session_start() 函數,才會產生相應的session文件和cookie值。

具體過程如下:

1、客戶端(瀏覽器)首次訪問時,這裏默認開啟了session_start() 函數的,此時PHP會隨機生成一個不重復的cookie(即session_id,這裏假如生成ug9gch0ns7nql4gjoe3jckdab2)

值。

2、服務端會生成一個session文件默認文件名為’SESS_’.session_id,即:SESS_ ug9gch0ns7nql4gjoe3jckdab2 文件。文件的保存路徑默認在php.ini的session.save_path設置的路徑中,例如linux系統中默認為/var/lib/php/sessions目錄。(註意:此時SESS_ ug9gch0ns7nql4gjoe3jckdab2文件是個空文件,因為服務端還沒有信息存入SESSION中,具體看第4步)

3、然後將生成的 ug9gch0ns7nql4gjoe3jckdab2 設置到cookie裏,cookie鍵名默認是php.ini裏設置的session.name配置項,默認是:session.name=PHPSESSID;相當於執行了$_COOKIE[‘PHPSESSID’]= ug9gch0ns7nql4gjoe3jckdab2;用戶此次訪問的http響應頭部信息裏就會包含:

Set-Cookie: PHPSESSID=ug9gch0ns7nql4gjoe3jckdab2; path=/

相應的cookie信息就會保存到客戶端。

4、用戶在登錄界面輸入用戶名和密碼並提交。此時瀏覽器會將用戶名和密碼和cookie值等信息提交到服務端。此時http請求的頭部信息會包含:Cookie:PHPSESSID=ug9gch0ns7nql4gjoe3jckdab2

5、當數據到達服務端,PHP會根據cookie內容找到session文件SESS_ ug9gch0ns7nql4gjoe3jckdab2 並將該文件讀入$_SESSION 變量。然後驗證用戶名和密碼。驗證通過了。就將該用戶的相關信息,比如用戶名、系統權限等寫入到$_SESSION 變量中。cookie沒有改變。腳本執行結束時,$_SESSION變量的值會被序列化後寫入SESS_ ug9gch0ns7nql4gjoe3jckdab2

驗證不通過,則跳轉回登錄頁,cookie沒有改變,$_SESSION也沒有新增值。

6、如果用戶完成登錄進入系統了,以後每訪問一個頁面,系統會獲取該客戶端瀏覽器傳過來的cookie值,然後根據cookie值獲取到對應的session文件,讀取session文件並解序列化寫入到內存中即$_SESSION變量中。接著服務端系統接口處會驗證該$_SESSON文件中是否有之前設置的用戶信息,如用戶名和系統權限等。如果有,則說明該用戶已經登錄,如果沒有,則說明該用戶登錄過期或者未登錄,跳轉到登錄頁面。

使用cookie來實現登錄就不會再使用到session了。如文章開頭所述,cookie實現登錄需要將用戶的信息進行單向加密。然後通過驗證該密文確認用戶是否已經登錄。也許大家會感覺使用session驗證登錄的步驟比cookie的簡單許多。其實只是需要我們處理的步驟比較少而已,有一部分是語言編譯器內部實現的。比如session文件的生成匹配。所以到我們自己操作的步驟就會相對較少。cookie實現登錄主要依靠單向加密驗證,比如用戶登錄時對”用戶名+用戶密碼+cookie過期時間+鹽”這些信息進行md5簽名,然後將該簽名放到cookie中,當然cookie值還包含用戶名和cookie值的過期時間,比如:admin_1533006028_ bbf2c2b1ec5cfb62d0a30438d8d0305c。後面用戶每次訪問都獲取到這個cookie值,拆分後根據用戶名和cookie值的過期時間,加上從數據庫獲取的用戶密碼和鹽值,進行md5簽名,然後對兩步簽名進行比對,如果一致,則說明是已登錄的用戶。

由於用戶每次訪問都要驗證cookie裏的簽名,也就是每次都要獲取用戶密碼和鹽值。一般這些信息都是存在數據庫中。所以使用cookie實現登錄,會對數據庫的用戶表造成極大的壓力。而session方式則不存在這個問題,因為session是存在文件中,用戶每次訪問,PHP會將該用戶對應的session文件讀入內存。然後再去訪問$_SESSION變量獲取。但是session這樣處理的缺點是,當用戶量特別多的時候,每個用戶都會產生一個session文件,這意味著服務器的壓力倍增。就算做分布式,也還要處理session的集群。

當然,session也可以寫入數據庫,或者寫入緩存。如果session寫入數據庫,那麽又回到剛才cookie每次訪問都要查詢數據庫的問題了。如果是寫入緩存,倒也是權宜之計。如果在使用cookie登錄的步驟中將用戶信息寫入緩存,那麽這種方式也可以減緩數據庫的壓力。每次驗證時如果緩存中沒有再去查詢數據庫。這樣也不失為一個可行之計。

當然,也可以對用戶表進行分表並作一主庫多從庫處理。在大用戶量情況下,單使用數據庫,應該也能支撐吧。

使用COOKIE實現登錄 VS 使用SESSION實現登錄