2015年7月25日补充更新:
最近又再研究UCenter同步登录的真正最优方案了,感谢@Mercedes+ 提供的思路——Discuz SSO。因之前对Discuz并不熟悉,是需要帮Client实现一个棘手的接口需求而稍稍研究了下Discuz,但并不深入(其实是Discuz代码太烂我根本不想看)。
目前Laravel4.2有一个Package可以实现同步登录的程序基础,地址:https://github.com/wehnhew/laravel4-ucenter
配置相对简单,配置完毕后仍然有一个Bug需要开发者注意,作者似乎也已经不维护Package了。
laravel4-ucenter/src/Wehnhew/Ucenter/uc_client/client.php
这2个if,改为>=1或>0。再将你Discuz的/uc_client/data/cache/apps.php文件内容粘贴到laravel4-ucenter/src/Wehnhew/Ucenter/uc_client/data/cache/apps.php 中覆盖即可。剩下的继续按照作者的Guide配置完毕,特别注意appid和appkey的配置,基本就可以用了。
作者对于package的优化还不足,只是直接搬运uc_server的代码到package里,并做了简单的dz通信就完事儿了。许多配置文件在vendor里,没有改为可配置的外部(Config::get())的配置文件夹中。这就导致了composer update/reqirure时bug再现和配置丢失的问题。 建议大家自己建立composer包管理维护这块代码。
其实discuz的sso,最大作用的就是康盛各个产品根目录的/uc.php了,它负责与ucenter通信。有兴趣深入研究的朋友可以看看源代码。
以下是旧文,有兴趣的朋友也可以看下,算是邪门歪道……=V= 但是也很有意思嘛。
项目应用说明
Laravel4.2编写开发一套在Discuz X 上的子栏目,因此需要获得当前在线账号的在线状态。
突破口
COOKIE
上网搜索了大量信息后总结一下我的实现方法。
首先简单说下实现方法:
1. incldue 你的config文件,一般是[你的discuz]/config/config_global.php
2. 配置文件中的$_config[‘cookie’][‘cookiepre’]就是你的COOKIE前缀,记住它。
3. 修改配置文件中的$_config[‘cookie’][‘cookiedomain’]为你的主域名,如:crazyphper.com
4. 在Discuz上登录后,访问你的Laravel程序。只要你们在同一个域名下(哪怕是二级域名的不同)现在也可以读取到来自Discuz的COOKIE了。如图1
5. 图中勾中的2个比较重要,可以全部赋值提出来存入一个变量方便后续调用。(提取出来的方法见6)
6. 使用正则和来自config文件中的COOKIE前缀,提取出这些COOKIE,正则代码可以参考下面这段:
$pre = $_config['cookie']['cookiepre']; $pattern = '/^'.$pre.'(.*)_sid$/'; foreach ($_COOKIE as $key=>$val) { if((substr($key,0,strlen($pre)))){ if(preg_match_all($pattern, $key,$r)){ $cookieKey = $r[1][0]; break; } } } if(empty($cookieKey)){ //不在线,返回“false” return false; }
7. $cookieKey就是COOKIE中间值,那个中间值是图片上的“592f”,每次登录都不一样的所以要用正则拿。
8. 使用authcode() 这个UCENTER的 function 对 COOKIE *_auth 的值进行解密,里面有用户密码和UID。你需要将UCENTER的authcode()移到你的laravel中,然后autoload噢,这个过程此处省略(你也可以放在当前Controller里做一个匿名方法或者private方法来调用;这样更快可以验证这篇博客的方法是否可行)。
9.authcode()方法中有一个地方调用了getglobal(‘authkey’)的方法,是利用config文件$_config[‘security’][‘authkey’]与$_COOKIE[‘*_auth’]进行MD5()后的密钥,因此你需要自己实现下,参考:
$saltkey = $pre . $cookieKey . '_saltkey'; $authKey = md5($_config['security']['authkey'].$_COOKIE[$saltkey]);
10.将daddslashes()同样移到自己的Laravel中。
11. 剩下的就是执行代码了,贴码子:
$auth = $pre.$cookieKey.'_auth'; $authDecode = daddslashes(explode("t", authcode($_COOKIE[$auth], 'DECODE','ca3e1823eb83455389efdf7be2b542f4'))); list($discuz_pw, $discuz_uid) = empty($authDecode) || count($authDecode) < 2 ? array('', '') : $authDecode;
12. 得到UID和密码,你就可以配合$_COOKIE[‘*_auth’]与ucenter数据库中的用户进行匹配,为真就代表在线有效。
注:
1 、 authcode()和daddslashes()在/source/function/function_core.php里。
2 、 如果放在laravel中的authcode()的返回值为空,一定是UC_KEY不正确,你可以用IDE(推荐PHPSTORM 9)工具的DEBUG模式运行你的discuz,然后在function_core.php 的authcode()中的UC_KEY处设置断点查看真正的KEY是多少。
3 、 别看uc_authcode()方法,那玩意儿压根没被用到,混淆视听。
最后提供下完整的参考代码:
/** * 获取当前在线用户信息 */ protected function getOnlineUser() { include '....../config/config_global.php'; //discuz 的配置文件,绝对路径噢 $pre = $_config['cookie']['cookiepre']; $pattern = '/^' . $pre . '(.*)_auth$/'; foreach ($_COOKIE as $key => $val) { if ((substr($key, 0, strlen($pre)))) { if (preg_match_all($pattern, $key, $r)) { $cookieKey = $r[1][0]; break; } } } if (empty($cookieKey)) { return false; } $sid = $pre . $cookieKey . '_sid'; $auth = $pre . $cookieKey . '_auth'; $saltkey = $pre . $cookieKey . '_saltkey'; // $lastvisit = $pre . $cookieKey . '_lastvisit'; $authKey = md5($_config['security']['authkey'].$_COOKIE[$saltkey]); $authDecode = daddslashes(explode(" ", authcode($_COOKIE[$auth], 'DECODE', $authKey))); list($discuz_pw, $discuz_uid) = empty($authDecode) || count($authDecode) < 2 ? array('', '') : $authDecode; if (!empty($discuz_pw) && !empty($discuz_uid) && !empty($_COOKIE[$sid])) { list($ip1, $ip2, $ip3, $ip4) = explode('.', Request::getClientIp()); $session = DB::table('common_session')->where('sid', $_COOKIE[$sid])->where('uid', $discuz_uid)->where('ip1', $ip1)->where('ip2', $ip2)->where('ip3', $ip3)->where('ip4', $ip4)->first(); if (empty($session)) { return false; } $this->uid = $discuz_uid; return true; } }
发表回复