網站記住賬號和自動登入功能實現
阿新 • • 發佈:2019-01-27
剛開始做這個功能的時候一頭霧水,本來打算直接用cookie實現,但發現在控制檯用document.cookie,就會完全暴露出使用者名稱和密碼,於是在網上找了各種辦法,但沒有找到一個很好的解決方案,最後想到在服務端設定cookie,並且經過加密來實現。
因為公司後端是php,所以以下用php為例。
前端部分:
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <title>記住密碼和自動登入</title> </head> <body> <div>賬號:<input type="text" id="account"></div><br> <div>密碼:<input type="password" id="password"></div><br> <div> <label for="remPassword"><input type="checkbox" id="remPassword">記住密碼</label> <label for="autoLogin"><input type="checkbox" id="autoLogin">自動登入</label> </div><br> <div><button type="button">登入</button></div> <script src="http://libs.baidu.com/jquery/2.0.3/jquery.min.js"></script> <!-- 引入jquery.cookie是為了演示方便,可以通過後端語言讀取cookie,並設定html --> <script src="https://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.min.js"></script> <script> /* *存在cookie則展示使用者名稱和密碼, *並選中記住密碼,注意使用者和密碼需要後端解密,並設定到頁面, *因為不方便演示,所以略過。 */ if($.cookie('account') && $.cookie('password')){ $('#remPassword').prop('checked',true); } $('button').bind('click',function(){ var account = $('#account').val(), password = $('#password').val(); if(!account || !password){alert('請輸入使用者名稱和密碼');return false;} var d = {account:account,password:password}; if($("#remPassword").is(":checked")){//記住密碼 d.remPassword = true; } if($("#autoLogin").is(":checked")){//自動登入 d.autoLogin = true; } $.post('login.php',d,function(data){ alert(data); },'text') }) //自動登入 if($.cookie('autoLogin')){ $('#autoLogin').prop('checked',true); //觸發登入 $('button').click(); } </script> </body> </html>
php部分(login.php):
<?php /* *該方法只是一個加解密的舉例 */ //$string:字串,明文或密文;$operation:DECODE表示解密,其它表示加密;$key:密匙;$expiry:密文有效期 function encrypt($string, $operation = 'DECODE', $key = 'key', $expiry = 0) { // 動態密匙長度,相同的明文會生成不同密文就是依靠動態密匙 $ckey_length = 4; // 密匙 $key = md5($key ? $key : $GLOBALS['discuz_auth_key']); // 密匙a會參與加解密 $keya = md5(substr($key, 0, 16)); // 密匙b會用來做資料完整性驗證 $keyb = md5(substr($key, 16, 16)); // 密匙c用於變化生成的密文 $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : ''; // 參與運算的密匙 $cryptkey = $keya.md5($keya.$keyc); $key_length = strlen($cryptkey); // 明文,前10位用來儲存時間戳,解密時驗證資料有效性,10到26位用來儲存$keyb(密匙b), //解密時會通過這個密匙驗證資料完整性 // 如果是解碼的話,會從第$ckey_length位開始,因為密文前$ckey_length位儲存 動態密匙,以保證解密正確 $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string; $string_length = strlen($string); $result = ''; $box = range(0, 255); $rndkey = array(); // 產生密匙簿 for($i = 0; $i <= 255; $i++) { $rndkey[$i] = ord($cryptkey[$i % $key_length]); } // 用固定的演算法,打亂密匙簿,增加隨機性,好像很複雜,實際上對並不會增加密文的強度 for($j = $i = 0; $i < 256; $i++) { $j = ($j + $box[$i] + $rndkey[$i]) % 256; $tmp = $box[$i]; $box[$i] = $box[$j]; $box[$j] = $tmp; } // 核心加解密部分 for($a = $j = $i = 0; $i < $string_length; $i++) { $a = ($a + 1) % 256; $j = ($j + $box[$a]) % 256; $tmp = $box[$a]; $box[$a] = $box[$j]; $box[$j] = $tmp; // 從密匙簿得出密匙進行異或,再轉成字元 $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256])); } if($operation == 'DECODE') { // 驗證資料有效性,請看未加密明文的格式 if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) { return substr($result, 26); } else { return ''; } } else { // 把動態密匙儲存在密文裡,這也是為什麼同樣的明文,生產不同密文後能解密的原因 // 因為加密後的密文可能是一些特殊字元,複製過程可能會丟失,所以用base64編碼 return $keyc.str_replace('=', '', base64_encode($result)); } } //登入操作 $account = $_POST['account']; $password = $_POST['password']; //如果設定記住賬號 設定cookie if(isset($_POST['remPassword'])){ $a = encrypt($account,'ENCODE'); $p = encrypt($password,'ENCODE'); setcookie("account",$a, time()+3600*24*7); setcookie("password",$p, time()+3600*24*7); }else{ //刪除cookie if(isset($_COOKIE['account']) && isset($_COOKIE['password'])){ setcookie ("account", "", time() - 3600); setcookie ("password", "", time() - 3600); } } //如果設定自動登入 設定cookie if(isset($_POST['autoLogin'])){ setcookie("autoLogin",$_POST['autoLogin'], time()+3600*24*7); }else{ //刪除cookie if(isset($_COOKIE['autoLogin'])){ setcookie ("autoLogin", "", time() - 3600); } } /* * 解密cookie,頁面初始化時展示出來 if(isset($_COOKIE["account"]) && isset($_COOKIE["password"])){ $account = encrypt($_COOKIE["account"],'DECODE'); $password = encrypt($_COOKIE["password"],'DECODE'); } */ echo '登入成功'.$account.'--'.$password; ?>
加解密方法是我從網上搜到的一個方法,也可以使用其他方法,只要能混淆cookie並防止他人解密就好,以上的cookie還可以把使用者名稱和密碼的部分相互替換(解密前先替換好),增加密文的複雜度,通過這些加密和混淆,即使別人獲取了cookie,也是難以破解的。
此外,還有一個安全問題,他人在獲取了電腦/手機的情況下,是可以通過dom元素獲取密碼的,所以頁面可以不展示解密後的密碼,只需寫入一串特定的符號,如果使用者進行登入時沒有改變,表示是要通過cookie中的密碼進行登入,後端進行解密再登入,這樣,只需關注cookie的安全性就好。