在使用PHP編程的時(shí)候,我有一個(gè)習(xí)慣,不太喜歡使用現(xiàn)成的庫(kù)文件,例如PHPLib或者其它類(lèi)似的庫(kù),在這個(gè)系統(tǒng)中,我也打算自己寫(xiě)一個(gè)庫(kù)文件,它需要處理認(rèn)證、確認(rèn)email,更新帳號(hào)(密碼,email)等事情。
為了在保證該系統(tǒng)安全的同時(shí),不會(huì)加重我現(xiàn)有數(shù)據(jù)庫(kù)的負(fù)擔(dān)。因此這個(gè)新的系統(tǒng)要依賴(lài)cookies。這確實(shí)是一個(gè)兩難的選擇,因?yàn)槿绻皇窃O(shè)置一個(gè)用戶(hù)名的cookie,是很不安全的,這行不通,但從數(shù)據(jù)庫(kù)的負(fù)擔(dān)考慮,我也不能加入一個(gè)簡(jiǎn)單的無(wú)序碼而交由我的數(shù)據(jù)庫(kù)來(lái)進(jìn)行驗(yàn)證。
解決的方法是同時(shí)設(shè)置兩個(gè)cookie,一個(gè)是用戶(hù)名的cookie,一個(gè)是無(wú)序碼的cookie。這個(gè)無(wú)序碼實(shí)際上是由用戶(hù)名和一個(gè)超級(jí)密碼(只有程序設(shè)計(jì)者知道)組合通過(guò)md5()函數(shù)運(yùn)算產(chǎn)生的。由于md5()是一個(gè)單向的無(wú)序碼,因此是不可以破解的。在用戶(hù)更改email時(shí),我也可以用該email和超級(jí)密碼產(chǎn)生一個(gè)無(wú)序碼,以讓用戶(hù)確認(rèn)修改。這實(shí)際上是一個(gè)公匙/私匙類(lèi)的系統(tǒng)。不明白?不要緊,下面再慢慢說(shuō)明。
有趣的是,這個(gè)系統(tǒng)的擴(kuò)展能力是可以達(dá)到無(wú)窮的,因?yàn)樵撓到y(tǒng)的主要工作是計(jì)算md5()函數(shù)的值,而且由web服務(wù)器完成,在負(fù)載增加時(shí),可以加入其它的服務(wù)器來(lái)分擔(dān)負(fù)載,雖然認(rèn)證系統(tǒng)不會(huì)拖跨一個(gè)數(shù)據(jù)庫(kù),但是這樣做就讓最終的瓶頸只能出現(xiàn)在數(shù)據(jù)庫(kù)上。
以下是該庫(kù)中的兩個(gè)函數(shù)--記號(hào)產(chǎn)生和記號(hào)認(rèn)證函數(shù)。
| 以下為引用的內(nèi)容: <?php $hidden_hash_var='your_secret_password_here'; $LOGGED_IN=false; function user_isloggedin() { file://如果是的話,返回該變量 if ( isset($LOGGED_IN) ) { return $LOGGED_IN; } file://are both cookies present? if ($user_name && $id_hash) { /* |
由cookies中得來(lái)的用戶(hù)名和系統(tǒng)超級(jí)密碼產(chǎn)生一個(gè)認(rèn)證用的無(wú)序碼如果該無(wú)序碼與cookie中的無(wú)序碼一樣,則cookies中的變量是可信的,用戶(hù)已經(jīng)登錄。
| 以下為引用的內(nèi)容: */ $hash=md5($user_name.$hidden_hash_var); if ($hash == $id_hash) { file://無(wú)序碼符合,設(shè)置一個(gè)全局變量,這樣我們?cè)谠俅握{(diào)用該函數(shù)的時(shí)候, file://就無(wú)需再次進(jìn)行md5()運(yùn)算 $LOGGED_IN=true; return true; } else { file://兩個(gè)無(wú)序碼不符合,沒(méi)有登錄 $LOGGED_IN=false; return false; } } else { $LOGGED_IN=false; return false; } } function user_set_tokens($user_name_in) { /* |
一旦用戶(hù)名和密碼通過(guò)驗(yàn)證,就調(diào)用這個(gè)函數(shù)
| 以下為引用的內(nèi)容: */ global $hidden_hash_var,$user_name,$id_hash; if (!$user_name_in) { $feedback .= ' ERROR - User Name Missing When Setting Tokens '; return false; } $user_name=strtolower($user_name_in); file://使用用戶(hù)名和超級(jí)密碼創(chuàng)建一個(gè)無(wú)序碼,作判斷是否已經(jīng)登錄用 $id_hash= md5($user_name.$hidden_hash_var); file://設(shè)置cookies的有效期為一個(gè)月,可設(shè)置為任何的值 setcookie('user_name',$user_name,(time() 2592000),'/','',0); setcookie('id_hash',$id_hash,(time() 2592000),'/','',0); } ?> |
再來(lái)看另一段有趣的代碼,用戶(hù)怎樣才能安全地改變他們的email地址呢?他們可以在任何時(shí)候改變email地址,但是要進(jìn)行確認(rèn)。
| 以下為引用的內(nèi)容: <?php function user_change_email ($password1,$new_email,$user_name) { global $feedback,$hidden_hash_var; if (validate_email($new_email)) { $hash=md5($new_email.$hidden_hash_var); file://改變數(shù)據(jù)庫(kù)中確認(rèn)用的無(wú)序碼值,但不改變email file://發(fā)出一個(gè)帶有新認(rèn)證碼的確認(rèn)email $user_name=strtolower($user_name); $password1=strtolower($password1); $sql="UPDATE user SET confirm_hash='$hash' WHERE user_name='$user_name' AND password='". md5($password1) ."'"; $result=db_query($sql); if (!$result || db_affected_rows($result) < 1) { $feedback .= ' ERROR - Incorrect User Name Or Password '; return false; } else { $feedback .= ' Confirmation Sent '; user_send_confirm_email($new_email,$hash); return true; } } else { $feedback .= ' New Email Address Appears Invalid '; return false; } } function user_confirm($hash,$email) { /* |
用戶(hù)點(diǎn)擊認(rèn)證email的相關(guān)連接時(shí),連到一個(gè)確認(rèn)的頁(yè)面,該頁(yè)面會(huì)調(diào)用這個(gè)函數(shù)
| 以下為引用的內(nèi)容: */ global $feedback,$hidden_hash_var; file://verify that they didn't tamper with the email address $new_hash=md5($email.$hidden_hash_var); if ($new_hash && ($new_hash==$hash)) { file://在數(shù)據(jù)庫(kù)中找出這個(gè)記錄 $sql="SELECT * FROM user WHERE confirm_hash='$hash'"; $result=db_query($sql); if (!$result || db_numrows($result) < 1) { $feedback .= ' ERROR - Hash Not Found '; return false; } else { file://確認(rèn)email,并且設(shè)置帳號(hào)為已經(jīng)激活 $feedback .= ' User Account Updated - You Are Now Logged In '; user_set_tokens(db_result($result,0,'user_name')); $sql="UPDATE user SET email='$email',is_confirmed='1' WHERE confirm_hash='$hash'"; $result=db_query($sql); return true; } } else { $feedback .= ' HASH INVALID - UPDATE FAILED '; return false; } } function user_send_confirm_email($email,$hash) { /* |
這個(gè)函數(shù)在首次注冊(cè)或者改變email地址時(shí)使用
| 以下為引用的內(nèi)容: */ $message = "Thank You For Registering at Company.com". "/nSimply follow this link to confirm your registration: ". } ?> |
評(píng)論:或許我們?cè)谟脩?hù)認(rèn)證方面不是采用這種方法,而是采用session等方式,不過(guò)這篇文章在如何進(jìn)行加密和確認(rèn)方面,還是對(duì)我們有所啟發(fā)的。
新聞熱點(diǎn)
疑難解答