ucenter1.5通訊過程分析

1,用戶登錄bbs,通過logging.php文件中,使用函數uc_user_login驗證,如果驗證成功,將調用函數uc_user_synlogin(位於uc_client下的client.php文件中),在這個函數中調用 uc_api_post('user', 'synlogin', array('uid'=>$uid));之後向UC_API.'/index.php'傳遞了數據;這裏的UC_API就是在config.inc.php中的定義的uc_server之URL地址
2,uc_server的index.php接受參數數據,獲得model爲user,action爲synlogin,就調用control目錄下的user.php類中的onsynlogin方法,通過foreach循環,以javascript的方式通知uc應用列表中的應用同步登錄;即通過get方式傳遞給應用目錄中api下的uc.php一些數據;
3,uc.php接收通知並處理get過來的數據,並在函數synlogin(位於uc.php中)通過函數_authcode加密數據(默認以UC_KEY作爲密鑰),用函數_setcookie設置cookie;
4,各個應用在適當的文件中用對應的密鑰解碼上面設置的cookie,得到用戶id等數據;通過這個值來判斷用戶是否經過其它應用登錄過;
-------------------------------------------------------------------------------------------------------
不同的應用加密的函數名稱可能不同,但密鑰相同情況下,加密結果是一樣的:
uc.php裏是_authcode,
client.php裏是uc_authcode,
\bbs\include\global.func.php裏是authcode
uchome\source\function_common.php裏是authcode
supersite\function\common.func.php裏是authcode
------------------------------------------------------------------------------------------------------
以discuz舉例:
 
一、用戶登錄檢查與用戶登錄驗證logging.php
在bbs的logging.php中如下代碼段
} elseif($action == 'login') {
if($discuz_uid) {
   $ucsynlogin = '';
   showmessage('login_succeed', $indexname);
}
 
檢查用戶id變量$discuz_uid是否爲空來判斷,用戶是否登錄(包括從別的應用登錄。)
如果用戶從bbs登錄,則在登錄驗證成功後通過如下代碼:
 
$ucsynlogin = $allowsynlogin ? uc_user_synlogin($discuz_uid) : '';
 
通知其它應用----“用戶已從bbs登錄,請通知其它應用設置cookie”
(uc_server通過javascript調用方式向其它應用的api/uc.php傳遞數據)
可以在uc應用目錄下新建一個名爲test.php的文件,來模擬登錄成功,請求uc_server通知其它應用。文件內容爲:
---------------------文件內容開始----------------------
<?php
include_once "config.inc.php";
include_once "./uc_client/client.php";
echo uc_user_synlogin(1);
echo "<pre>";
var_dump($_COOKIE);
echo "</pre>";
?>

<script type="text/javascript">
var obj=document.getElementsByTagName("script");
for(var i=0;i<obj.length-1;i++) {
   document.write("<a href=\""+obj[i].src+"\">"+obj[i].src+"</a><hr>");
}
</script>
---------------------文件內容結束----------------------
ps:這段測試代碼還可以測試同步登錄不好使的情況,具體使用方法,你可以思考一下(本文後面也有介紹),有問題可以在此文結尾發表評論與我討論
運行後,查看源代碼即可看到javascript;
這裏要注意了:這些javascript的通知中是不包含用戶登錄的應用的。也就是說只"通知"用戶未登錄的應用,因爲用戶通過uc_server登錄成功的當前應用,當然不需要uc_server再通知了。具體代碼請參看:webroot\uc_server\control\user.php中的onsynlogin函數的這句:
if($app['synlogin'] && $app['appid'] != $this->app['appid'])
代碼解釋:
$app['synlogin']是uc應用是否允許同步登錄
而且應用id不等於用戶當前登錄的應用id
$app數組就是uc_server\data\cache\apps.php中的數組$_CACHE['apps'];
$this->app就是用戶登錄的應用
二、接受其它應用的同步登錄通知:
在discuz的api目錄下的uc.php中的函數synlogin,在這裏接受uc_server發送過來的“同步登錄通知”,並設置discuz的cookie,在這個函數中你可以查看到cookie的加密密鑰的“算法”;
如果你想看看uc_server發送過的的“通知”是什麼數據,你可以這麼做:
1,修改要接受通知的應用目錄下的api\uc.php,在$action = $get['action'];代碼下面添加如下代碼:
echo "<pre>";var_dump($get);echo "</pre>";die("<hr>api\uc.php");
2,將上面建立的test.php文件放置在其它允許同步登錄的應用目錄下,並在瀏覽器中運行,然後點擊頁面中對應第一步的應用鏈接,即可看到uc_server“通知”給該應用的數據;
---------------------------分割線-------------------------------
function synlogin($get, $post)
在這個函數中通過_authcode函數,以密鑰$discuz_auth_key加密了cookie;
在這裏爲了避免cookie名稱衝突,在cookie名稱(一般爲:auth)前加了前綴($cookiepre),這個前綴也就是在config.inc.php中設置的那個cookie前綴值;
請看設置cookie的函數_setcookie:
(通過參數$prefix來判斷是否對cookie名稱添加前綴$cookiepre)
function _setcookie($var, $value, $life = 0, $prefix = 1) {
global $cookiepre, $cookiedomain, $cookiepath, $timestamp, $_SERVER;
setcookie(($prefix ? $cookiepre : '').$var, $value
,
  $life ? $timestamp + $life : 0, $cookiepath
,
   $cookiedomain, $_SERVER['SERVER_PORT'] == 443 ? 1 : 0);
}
密鑰“算法”:
$discuz_auth_key= md5($_DCACHE['settings']['authkey'].$_SERVER['HTTP_USER_AGENT']);
也就是不同用戶加密cookie的密鑰可能不同;
三、檢查用戶是否已登錄(無論是那個應用下登錄):
discuz的include目錄中common.inc.php中有這樣的代碼:

$discuz_auth_key = md5($_DCACHE['settings']['authkey'].$_SERVER['HTTP_USER_AGENT']);
list($discuz_pw, $discuz_secques, $discuz_uid) = empty($_DCOOKIE['auth']) ? array('', '', 0) : daddslashes(explode("\t", authcode($_DCOOKIE['auth'], 'DECODE')), 1);
這段代碼就是解碼在uc.php中用密鑰($discuz_auth_key)加密的cookie值,以獲得用戶id($discuz_uid)
這裏的解密函數位於bbs\include\global.func.php中,雖然未給函數傳遞cookie密鑰,但函數中通過全局變量$GLOBALS['discuz_auth_key'])獲得密鑰。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章