JSP網站與phpwind論壇同步登入的解決思路
在上一篇文章中,筆者介紹了在Windows上安裝Apache、PHP、MySQL等軟體的過程,以及Apache與Resin整合的方法。在這篇文章中,筆者將介紹JSP網站如何與phpwind論壇實現同步登入和同步退出的方案思路。本文以phpwind 7.5 SP3的源碼為例,但由於筆者曾在源碼中插入過一些測試代碼,後雖作了刪除,但尚不保證下文中所示代碼的行數完全與源碼一致,請自行在提示行數所定位的上下幾行中尋找。
一、phpwind的Cookie是如何產生的
phpwind是通過Cookie的方式來判斷目前使用者是否已經登入,因此要實現JSP網站與phpwind同步登入和同步退出功能的要點,就在於JSP網站的程式能捕獲並分析phpwind產生的Cookie,同時JSP網站的程式還應能產生同樣的Cookie,以便訪問phpwind論壇時可以自動登入。下面來看下phpwind對於登入使用者所產生的Cookie的資訊:
在的Cookie資訊中,08383_winduser及其所對應的值就是判斷phpwind登入與退出狀態的依據,對它的分析也是本文的重點所在。
先來看下08383_winduser中08383是如何產生的。在login.php檔案的84行找到:
Cookie("winduser",StrCode($winduid."\t".$windpwd."\t".$safecv),$cktime);
Cookie函數的作用就是向用戶端寫Cookie,其函數定義在common.php檔案的145行:
function Cookie($ck_Var,$ck_Value,$ck_Time='F',$p=true){ }
從中可知第一個參數是Cookie的鍵名,第二個參數是Cookie的值,這樣通過函數調用傳遞給$ck_Var的值就是winduser,但我們在Cookie資訊中看到的卻是08383_winduser,那麼這08383是從何而來呢?細看下面的代碼,我們會發現在173行有這樣的語句:
$ck_Var = CookiePre().'_'.$ck_Var;
看來08383必定是由CookiePre函數所產生的,找到189行CookiePre函數的定義:
function CookiePre() {
static $pre = null;
!isset($pre)
&& $pre = substr(md5($GLOBALS['db_sitehash']),0,5);
return $pre;
}
這就知道了原來此08383是md5($GLOBALS['db_sitehash'])的前5個字元,而$GLOBALS['db_sitehash']是pw_config表中的資料db_sitehash所對應的值,這樣鍵名的產生過程就清楚了。下面再來看如何產生索引值。
從上文中可知索引值其實就是StrCode($winduid."\t".$windpwd."\t".$safecv),看common.php檔案中第241行background:white;'>StrCode函數的定義:
function StrCode($string,$action='ENCODE') { }
可以知道第一個參數是被加密或解密的字串,第二個參數是表示加密(ENCODE)或是解密(DECODE),預設為加密。其代碼中$GLOBALS['pwServer']['HTTP_USER_AGENT']表示的是Request請求中的User-Agent頭資訊,$GLOBALS['db_hash']
是pw_config表中的資料db_hash所對應的值。那麼傳遞給background:white;'>StrCode函數的實參$winduid."\t".$windpwd."\t".$safecv又是如何產生的呢?
在login.php檔案的第66與70行分別有如下代碼:
$logininfo = checkpass($pwuser, $md5_pwpwd, $safecv, $lgt);
list($winduid, $groupid, $windpwd, $showmsginfo) = $logininfo;
由此可知StrCode宋體;">函數的實參是由checkpass函數產生的,在checkpass.php檔案第49行找到checkpass函數的定義:
function checkpass($username, $password, $safecv, $lgt=0) { }
可以知道第一個參數是使用者名稱,第二個參數是md5加密過的使用者密碼,第三個參數是經過處理的使用者安全問題。其傳回值中的第一個值、第三個值分別與background:white;'>StrCode函數實參中的$winduid、$windpwd相對應,其中$winduid為pw_members表中對應的uid。而$windpwd的產生較為複雜,在第111行可以看到如下代碼:
$windpwd = PwdCode($password);
因此可知$windpwd是由PwdCode函數所產生的,在common.php檔案的第227行找到PwdCode函數定義:
function PwdCode($pwd) {
return md5($GLOBALS['pwServer']['HTTP_USER_AGENT'].$pwd.$GLOBALS['db_hash']);
}
這樣就明白了,$windpwd其實就是Request請求中的User-Agent頭資訊的字串、用md5加密過的使用者密碼、pw_config表中資料db_hash所對應值,三者依次拼接而成的字串進行一次md5加密之後所產生的字串,真是夠複雜的,看來phpwind為了安全也是煞費苦心啊!
最後StrCode宋體;">函數實參中就剩下$safecv了,它是由questcode函數產生,在checkpass.php檔案的第211行找到questcode函數的定義:
function questcode($question,$customquest,$answer) {
$question = $question=='-1' ? $customquest : $question;
return $question ? substr(md5(md5($question).md5($answer)),8,10) :
'';
}
$safecv的產生過程也夠複雜的,相信大家通過上面的講解也能明白這個產生過程了,那麼筆者也就不多費口舌,太累人了!
二、phpwind是如何從Cookie中擷取資訊
Phpwind從Cookie中擷取使用者資訊的代碼在global.php檔案第152行:
list($winduid,$windpwd,$safecv)=explode("\t",addslashes(StrCode(GetCookie('winduser'),'DECODE')));
其重點在於StrCode(GetCookie('winduser'),'DECODE'),作用是將從Cookie中擷取的值採用base64方式進行解碼。解碼之後的字串用"\t"分割為三段,第一段是uid,第二段是由上文所提到的PwdCode函數產生的字串,第三段是由上文所提到的questcode函數產生的欄位串,分別存入$winduid、$windpwd與$safecv中。之後就可以通過該uid來擷取使用者資訊,並驗證相關的密碼與安全問題是否一致了。
三、實現與phpwind論壇同步登入和同步退出的思路
要做到同步登入和同步退出,即使用者在JSP網站這邊登入後訪問phpwind時使用者已為登入狀態,在phpwind登入後訪問JSP網站也為登入狀態,退出亦然。這樣就要求在JSP網站這邊用java實現兩個功能,一個是從Cookie中讀取由phpwind產生的winduser的值並加以解析,另一個是使用者登入時採用類似於phpwind的方式產生Cookie,以便phpwind論壇識別使用者狀態。由於實現的代碼較為簡單,只要將上文提到的這些函數翻譯成java的代碼就行了,因此筆者在此主要介紹一下思路和可能遇到的問題。
對於從Cookie中讀取由phpwind產生的winduser的值並加以解析,筆者是將這部分代碼寫在一個Filter裡。在此Filter中,讀取Cookie中的值然後調用StrCode函數進行解碼,從而得到uid。之後通過uid查詢資料庫得到使用者物件,驗證其密碼與安全問題是否正確。如果都正確的話,則將使用者物件存入Session中。下次需要用到該使用者物件時,直接從Session中擷取,而不再通過調用StrCode函數進行解碼及查詢資料庫得到使用者物件。
這其中要注意解決的問題是,由於採用在Session中傳遞使用者物件,可能會出現phpwind論壇已經退出或改換使用者重新登入,但是在另一瀏覽視窗訪問的JSP網站,由於Session中的對象沒有失效,繼續訪問別的頁面時還處於原使用者登入狀態。筆者的解決方案是設定一個靜態變數來儲存Cookie中winduser的值,一旦發現新值變空或與原保留值不同,則說明在phpwind論壇那邊已經退出或以新使用者名稱登入了。
對於JSP網站這邊,使用者登入時調用StrCode函數來產生類似phpwind方式的Cookie,這樣以便phpwind論壇識別使用者狀態。此外,為了使phpwind與JSP網站共用一個Cookie,需要修改phpwind中的config.php檔案,將$db_ckdomain設定“.XXX.com”的形式。同步退出的實現較為簡單,只要將Cookie中的值置空即可,筆者在此不再贅述。
好了,在本文中筆者主要介紹了phpwind的Cookie產生方式,以及phpwind是如何從Cookie中擷取資訊,並簡要介紹了與phpwind論壇實現同步登入的思路。在下一篇文章中,筆者將介紹一下如何將Oracle中的資料快速便利的匯入到MySQL之中。