依照下列答案的意見後存在的問題,客戶端能夠登錄,在沒有任何問題,但並沒有試圖實際導航保護的頁面。當他稍後嘗試這樣做時,他會像以前一樣返回登錄,並顯示「請登錄」錯誤。想到很多頭腦之後,想到了一件令人難以置信的簡單事情 - 客戶端訪問該網站的時間爲http://www.example.com/admin,登錄腳本中的所有內容都重定向到http://example.com,因此它正在查找的會話cookie已設置爲另一個域。這也解釋了爲什麼他第一次登錄時遇到問題,但沒有後續登錄 - 腳本將他重定向到沒有www的登錄表單。
一個快速解決方案是編寫一個.htaccess文件來解決www問題。當然,這也可以在登錄腳本中處理,我將改進以備將來使用。
原帖
我開發了家釀CMS和登錄系統,PHP和MySQL基礎的網站。我的CMS對每個客戶都是獨一無二的,而且它一直都是人羣中的焦點 - 不幸的是,我的登錄系統並非如此。以下是一篇很長的文章,但我需要覆蓋細節以嘗試找到解決方案。忍受我..
該系統是相當直接,如果不是一個巨大的。每個用戶在SALT旁邊都有一個存儲在MySQL表中的鹽味散列。當用戶登錄時,他們的SALT被檢索並且提交的密碼變成一個含鹽散列。
如果提交的salted哈希值與表中存儲的哈希值相匹配,則認證用戶。諸如名稱,最後IP地址和帳戶級別(大多數站點上的3個級別)等詳細信息存儲在分配給會話變量的數組中。然後,他們被重定向到他們登錄的受限站點的登錄頁面(僅限會員或Admin/CMS)。
安全頁面包含一個較小的auth.php文件,用於檢查包含其詳細信息的會話變量是否存在。如果不是,則會將其重定向到該網站的登錄表單,並顯示一條錯誤消息,內容爲「請登錄」。如果存在,則允許它們繼續,並將存儲在數組中的細節分配給變量。
許多用戶報告的問題是,他們經常需要多次登錄以避免被「請登錄」錯誤消息彈回到登錄表單,或者他們導航到另一個頁面在安全網站中隨機彈出並返回登錄,並顯示相同的錯誤。所以,session變量似乎沒有被設置,或者在正常使用站點期間出於某種原因被清除。
第一個問題從來沒有發生在我身上 - 通過多種設備和網絡 - 我已經在客戶辦公室使用他們的筆記本電腦目睹了它。我讓他們連接到我的移動熱點,並沒有改變。但是,他們能夠使用我的筆記本電腦和我的熱點連接無任何問題地登錄。不幸的是,我無法使用我的筆記本電腦連接到他們的網絡,因此無法排除變量。
* 注 - *我忘了最初提及的是,系統正常工作的問題客戶,他們使用正確的憑據登錄兩次或三次之後。在瀏覽器保持打開的狀態下進行的後續登錄嘗試往往在未出現問題的情況下執行。此外,登錄頁面會破壞會話。
這裏是每一級的代碼,開始與登錄腳本:
的login.php
<?php
putenv("TZ=US/Eastern");
if (array_key_exists('site', $_POST)) {
$authenticate = new loginUser($_POST['username'], $_POST['password'], $_POST['site'], $_SERVER['REMOTE_ADDR']);
}
//Authenticate and log-in
class loginUser {
private $memDB, $username, $password, $site, $ip_address;
//Clean input variables
private function clean($str) {
$str = @trim($str);
if(get_magic_quotes_gpc()) {
$str = stripslashes($str);
}
return $str;
}
//Construct variables
function __construct($username, $password, $site, $ip_address) {
session_start();
$this->memDB = new PDO('mysql:host=localhost;dbname=exampleDB', 'exampleUser', 'examplePassword');
$this->username = $this->clean($username);
$this->password = $this->clean($password);
$this->site = $site;
$this->ip_address = $ip_address;
$this->authUser();
}
//Validate username
private function validateUsername($username) {
$checkUsername = $this->memDB->prepare("SELECT COUNT(*) FROM accounts WHERE username = ?");
$checkUsername->execute(array($username));
return $checkUsername->fetchColumn();
}
//Obtain and set account details
private function accountDetails() {
$fetchAccountDetails = $this->memDB->prepare("SELECT id, name_f, name_l, ipAddr, lastLogin, accountLevel, isActive
FROM accounts WHERE username = ?");
$fetchAccountDetails->execute(array($this->username));
$accountDetails = $fetchAccountDetails->fetch();
$this->updateLogin();
return $accountDetails;
}
//Update last login details
private function updateLogin() {
$updateLogin = $this->memDB->prepare("UPDATE accounts SET ipAddr = ?, lastLogin = DATE_ADD(NOW(), INTERVAL 1 HOUR) WHERE username = ?");
$updateLogin->execute(array($this->ip_address, $this->username));
}
public function authUser() {
$loginErr = array(); //Array for holding login error message
$loginErrFlag = false; //Boolean for error
//Validate submitted $_POST elements
if (!$this->username) {
$loginErr[] = "Username missing";
$loginErrFlag = true;
}
if (!$this->password) {
$loginErr[] = "Password missing";
$loginErrFlag = true;
}
if ($this->username && $this->validateUsername($this->username) == 0) {
$loginErr[] = "Username invalid";
$loginErrFlag = true;
}
if (!$loginErrFlag) {
//Fetch the password and SALT to compare to entered password
$validatePW = $this->memDB->prepare("SELECT password, salt FROM accounts WHERE username = ? LIMIT 1");
$validatePW->execute(array($this->username));
$passwordResult = $validatePW->fetch();
$dbPW = $passwordResult['password'];
$dbSalt = $passwordResult['salt'];
//Compare entered password to SALT + hash
$hashPW = hash('sha512', $dbSalt . $this->password);
if ($hashPW === $dbPW) {
//Logged in
$_SESSION['CVFD-USER-DETAILS'] = $this->accountDetails();
//Redirect to secure landing page for log-in origin (Members or Admin)
//Adding SID is a recent attempt to handle log-in problems
header("Location: http://example.com/$this->site/$this->site-main.php?" . SID);
//session_write_close() was here but was removed
exit();
} else {
//Password invalid
$loginErr[] = "Please check your password and try again";
$_SESSION['CVFD_LOGIN_ERR'] = $loginErr;
//Redirect to the log-in for the origin
header("Location: http://example.com/$this->site");
session_write_close();
exit();
}
} else {
$_SESSION['CVFD_LOGIN_ERR'] = $loginErr;
header("Location: http://example.com/$this->site");
session_write_close();
exit();
}
}
}
?>
auth.php
<?php
session_start();
if (!isset($_SESSION['CVFD-USER-DETAILS']) || $_SESSION['CVFD-USER-DETAILS'] == '') {
//Not logged in
$_SESSION['CVFD_LOGIN_ERR'] = array('Please login');
header('Location: http://example.com/members');
session_write_close();
exit();
} else {
$userDetails = $_SESSION['CVFD-USER-DETAILS']; //Assign user details array to variable
//Check to see if account is active
$accountStatus = $userDetails['isActive'];
$accountLevel = $userDetails['accountLevel'];
if ($accountStatus == 0) {
//Account is not yet active (pending Admin activation)
$_SESSION['CVFD_LOGIN_ERR'] = array('Your account is suspended or pending activation');
header('Location: http://example.com/members');
session_write_close();
exit();
} else {
$CVFDFirstName = $userDetails['name_f'];
$CVFDLastName = $userDetails['name_l'];
$CVFDLastLogin = date("m/d/Y H:i:s", strtotime($userDetails['lastLogin']));
$CVFDAccountLevel = $userDetails['accountLevel'];
$CVFDIPAddr = $userDetails['ipAddr'];
}
}
?>
這裏是auth.php如何包含在安全文件中 -
<?php
if (substr_count($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')) ob_start("ob_gzhandler"); else ob_start();
require($_SERVER['DOCUMENT_ROOT'] . '/members/includes/handlers/handler.auth.php');
任何幫助,將不勝感激。相當神祕..
謝謝!
所以你不能重現這個問題呢? – MrCode
從我的設備和網絡,沒有。第二個問題 - 在使用CMS期間隨機地重新登錄註冊 - 偶爾發生在我身上。大多數客戶使用IE和Windows,儘管投訴最多的客戶在他的iPhone,iPad,Windows NT筆記本電腦上使用IE 9和Chrome都存在問題。當他在家中並且在所有設備上工作時都會出現問題。 – NightMICU
我也確認了在他的設備和瀏覽器中啓用了Cookie。我親自目睹了這個問題。不過想到一個重要的問題 - 增加了原始問題 – NightMICU