1. 程式人生 > >PHP判斷使用者登入狀態

PHP判斷使用者登入狀態

1,瀏覽器URL訪問頁面資源,
2,檢視SESSION會話是否記錄登陸狀態,如“否”從3繼續,如“是”則到5
3,獲取瀏覽器客戶端的COOKIE使用者標識資訊,如果存在使用者資訊則繼續4,如“否”或者不符合既定原則 則到6
4,判斷使用者標識是否可信,比如將加密的字串解密,取出字串中的id和密碼與資料庫中資訊對比是否匹配,如果匹配則到5,如果不匹配則6
5,驗證登陸狀態通過
6,驗證登陸狀態不通過

如此看怎麼會老是讀資料庫呢?

分割線

一般常規“記住登陸”方法,可以將ID和密碼組合成字串再salt加密後存到瀏覽器客戶端。每次和伺服器端驗證時,再解密分割取得ID和密碼與資料庫比對。如此安全性還是可以的。

比如這是存到客戶端COOKIE

$data      = $id . "\t" . md5( $password . $slat); //$slat可以是硬編或者隨機存在使用者列的值
$identity  = base64_encode( encrypt( $data , $key ) );//encrypt為自實現的加密函式或方法,$key 可以是硬編或者隨機存在使用者列的值
setcookie("testuser", $identity, time()+3600);

比如這是取

if(isset($_COOKIE['testuser']))
{
    $identity = $_COOKIE['testuser'
]; list($id, $password) = explode("\t", decrypt( base64_decode( $identity ) , $key));//decrypt為自實現的解密函式或方法,$key 可以是硬編或者隨機存在使用者列的值 //todo 與資料庫列值比對 //... }

==========================

使用者資訊儲存至COOKIES中。
使用者資訊包括:UID,USERNAME,EMAIL,PASSWORD。
其中 EMAIL,PASSWORD進行可逆加密。
每次登入只須將COOKIES進行一次可逆加密和你資料庫對比一次若相等則登入,否則進行正常的登入操作。

===============

PS

======================

關於cookies中是否可以存放使用者資訊,一直都是業界存在爭議的一點。
目前我的解決方法是:
cookies中存放有關於郵箱、QQ號碼、使用者密碼、使用者名稱等資訊均需要進行可逆加密。
如有使用者資訊:

array("uid"=>1,"username"=>"b","password"=>"1234567","email"=>"[email protected]");

那麼,我將uid,username,password,email等資訊分別存放與cookies中,並且將username,password,email通過key(key只能自己知道和設定)進行可逆加密。當每一次需要操作的時候,我只需要$_COOKIE['password']然後將其解密還原為原始的1234567即可,然後將其進行查詢匹配。若查詢相同則認為該COOKIES有效,若不匹配則刪除cookies。

那麼,解密之後查詢認證有兩種方法:

1.直接連線資料庫進行SQL查詢,這是一種消耗效能的低效方法。

select username,uid,password from xxxx where uid='xxxx',username='xxxxx' LIMIT 1;

這種方法沒操作一次需要進行一次SQL查詢,將大大增加效能開銷。

2.將使用者第一次登入查詢出來的資訊加密儲存在cookies的同時,copy儲存一份至memcached記憶體中,並增加標識 uid_status(可自取) 為 1 (登入狀態),每一個使用者擁有一個唯一的uid_status,並且設定為長期有效。

判斷是否登入的過程則更加高效和快速。

將cookies中的資訊解密之後,檢視uid_status的狀態,若為1,直接認定該使用者處於登入狀態,不刪除cookies資訊。若為0,非登入狀態,則將cookies和memcached中的使用者資訊進行匹配。匹配包括:password,uid,username。若其中一項不正確則刪除cookies,更新uid_status狀態。

以上就是我判斷使用者是否登入過程。

========

P.S

===========

DISCUZ!系列是採用cookies加密後直接查詢資料庫進行cookies有效判斷的。

uc_home核心程式碼是:

<?php
//判斷當前使用者登入狀態
function checkauth() {
	global $_SGLOBAL, $_SC, $_SCONFIG, $_SCOOKIE, $_SN;

	if($_SGLOBAL['mobile'] && $_GET['m_auth']) $_SCOOKIE['auth'] = $_GET['m_auth'];
	if($_SCOOKIE['auth']) {
		@list($password, $uid) = explode("\t", authcode($_SCOOKIE['auth'], 'DECODE'));
		$_SGLOBAL['supe_uid'] = intval($uid);
		if($password && $_SGLOBAL['supe_uid']) {
			$query = $_SGLOBAL['db']->query("SELECT * FROM ".tname('session')." WHERE uid='$_SGLOBAL[supe_uid]'");
			if($member = $_SGLOBAL['db']->fetch_array($query)) {
				if($member['password'] == $password) {
					$_SGLOBAL['supe_username'] = addslashes($member['username']);
					$_SGLOBAL['session'] = $member;
				} else {
					$_SGLOBAL['supe_uid'] = 0;
				}
			} else {
				$query = $_SGLOBAL['db']->query("SELECT * FROM ".tname('member')." WHERE uid='$_SGLOBAL[supe_uid]'");
				if($member = $_SGLOBAL['db']->fetch_array($query)) {
					if($member['password'] == $password) {
						$_SGLOBAL['supe_username'] = addslashes($member['username']);
						$session = array('uid' => $_SGLOBAL['supe_uid'], 'username' => $_SGLOBAL['supe_username'], 'password' => $password);
						include_once(S_ROOT.'./source/function_space.php');
						insertsession($session);//登入
					} else {
						$_SGLOBAL['supe_uid'] = 0;
					}
				} else {
					$_SGLOBAL['supe_uid'] = 0;
				}
			}
		}
	}
	if(empty($_SGLOBAL['supe_uid'])) {
		clearcookie();
	} else {
		$_SGLOBAL['username'] = $member['username'];
		if($_SGLOBAL['connect']) {
			cloud_token();
		}
	}
}
?>

==========================================

cookie中怎麼能夠儲存密碼呢?

你的做法已經可以了,不過有如下幾點建議:
1. 客戶端可以儲存兩種資料,一種是原資料(比如user_id),一種是對所有原資料的簽名(你所說的加密碼)
2. 原資料的儲存可以看具體情況儲存原字串或者可逆加密演算法加密後的字串
3. 針對所有的原資料的簽名的演算法,最好是不可逆的
4. 伺服器端只要獲取到原資料,重新計算簽名,比如和cookie中的簽名是否一致即可。

最簡單的cookie的樣子:
A=uid=123&sign=xxxxxxxx

cookie生成方法:
sign = md5(secure_key + uid);
cookie = 'uid=' + uid + '&sign=' + sign
secure_key 是一個私有的串,誰也不能告訴哦。

cookie校驗的方法:
獲取到uid和sign之後
sign == md5(secure_key + uid)

當然如果覺得md5不可靠的話,可以選擇更好的演算法。