konakona
Laravel 4.2 与UCenter 同步在线(跨域)[最优解决方案]
Laravel 4.2 与UCenter 同步在线(跨域)[最优解决方案]

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

http://blog.crazyphper.com/wp-content/uploads/2015/07/QQ20150725-1@2x-300x170.jpg

这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

http://blog.crazyphper.com/wp-content/uploads/2015/07/QQ20150704-1@2x-300x59.jpg

图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;

        }
    }

 

 

 

 

赞赏
首页      程序开发      PHP      Laravel 4.2 与UCenter 同步在线(跨域)[最优解决方案]
https://secure.gravatar.com/avatar/3b712b34a0e1b689cfb524c9c6bcdc47?s=256&r=g

团哥

文章作者

继续玩我的CODE,让别人说去。 低调,就是这么自信。

发表评论

textsms
account_circle
email

konakona

Laravel 4.2 与UCenter 同步在线(跨域)[最优解决方案]
2015年7月25日补充更新: 最近又再研究UCenter同步登录的真正最优方案了,感谢@Mercedes+ 提供的思路——Discuz SSO。因之前对Discuz并不熟悉,是需要帮Client实现一个棘手的接口需求而稍…
扫描二维码继续阅读
2015-07-04