Discuz 3.X 整合 CAS 的方法

有很多朋友问我为什么没能整合成功?

     我也没有能及时回复,在此表示抱歉。

 

实际上将登录的过程是在Cas Server 登录页面 中完成的, DZ中的登录用户名密码这些都可以隐藏掉。 这个需要改模板了。

1,点登录按钮,跳到CAS。

2,在CAS 登录完成后,跳回Dz,这个回调的Url会有一个ticket 。

3,DZ会根据这个ticket,通过后台去CAS Server验证这个ticket是否有效。

4,如果有效就置用户为登录状态。

 

其实没有整合成功是很正常的,因为我使用Server不是Java版的,是我自已重新在原有业务系统上根据CAS协议做的。与标准的有一点点差别。

下面是13年写的,只做参考即可。原理方面的东西是一致的。

没有整合成功的:

1,注意一下这个,这个是关键

     phpCAS::getAttribute ...

     在CasServer 返回回应中(上面说的过程中第三步) 中可以设置 attribute ,Cas Server , (java 版的在读代码的时候,见到过类似的设置)

 

   代码中用到的

 $email = phpCAS::getAttribute('Email');
  $uid = phpCAS::getAttribute('Uid');

   这个email , uid  都是 cas server 自定义的。其实你的返回的并一定有这几,你也可以根据自己的业务情况,自定其它的返回,只要能标记用户就行了。

 

2, userloginCas  这个方法是我自己的写的,

    它的功能就是把上面返回的数据,进行加工,让DZ ”以为“ 数据是真的。

 

                                                                                                             

————————————————————————————————————2015-11-24 更新————————————————————————————————————————————

 

1,新建 CasClient.php

<?php
include_once (dirname ( __FILE__ ) . '/CasClientConfig.php'); // 注意这个
include_once (dirname ( __FILE__ ) . '/CAS.php'); // 注意这个
                                                  
// 初始化
phpCAS::setDebug ();
 
// initialize phpCAS
phpCAS::client ( CAS_VERSION_2_0, CAS_SERVER_HOSTNAME, CAS_SERVER_PORT, CAS_SERVER_APP_NAME );
 
// no SSL validation for the CAS server
phpCAS::setNoCasServerValidation ();

 

 

2,新建 CasClientConfig.php

 
// define ( 'CAS_SERVER_HOSTNAME', 'caslocal.youxituan.com' );
// define ( 'CAS_SERVER_PORT', 80 );
define ( 'CAS_SERVER_HOSTNAME', 'localhost' );
define ( 'CAS_SERVER_PORT', 34382 );
define ( 'CAS_SERVER_APP_NAME', "cas" );
define ( 'LocalLoginPath', '/cas/localogin.php' );
define ( 'LocalCheckPath', '/cas/logincheck.php' );
define ( 'LocalLogOffPath', '/cas/logoff.php' );

 

3, 修改 class_core.php

error_reporting(E_ALL);
 
define('IN_DISCUZ', true);
define('DISCUZ_ROOT', substr(dirname(__FILE__), 0, -12));
define('DISCUZ_CORE_DEBUG', false);
define('DISCUZ_TABLE_EXTENDABLE', false);
require_once DISCUZ_ROOT."Cas/CasClient.php";
set_exception_handler(array('core', 'handleException'));
 
if(DISCUZ_CORE_DEBUG) {

 

3,修改  function_member.php 支持 CAS 登录

 

增加一个方法

// 新加的方法,用以支持CAS 登录
function userloginCas($username, $password, $email, $uid) {
    $return = array ();
    $merge = 0;
    $status = $uid;
    $mockcallback = array($uid, $username, $password, $email, $merge);
    
    $return ['ucresult'] = $mockcallback;  
//     $return ['ucresult'] ['status'] = 0;
//     $return ['ucresult'] ['username'] = $username;
//     $return ['ucresult'] ['password'] = $password;
//     $return ['ucresult'] ['email'] = $email;
//     $return ['ucresult'] ['uid'] = $uid;
//     $return ['ucresult'] ['merge'] = $merge;
    // }
    $tmp = array ();
    $duplicate = '';
    list ( $tmp ['uid'], $tmp ['username'], $tmp ['password'], $tmp ['email'], $duplicate ) = $return ['ucresult'];
    $return ['ucresult'] = $tmp;
    if ($duplicate && $return ['ucresult'] ['uid'] > 0 || $return ['ucresult'] ['uid'] <= 0) {
        $return ['status'] = 0;
        return $return;
    }
    
    $member = getuserbyuid ( $return ['ucresult'] ['uid'], 1 );
    if (! $member || empty ( $member ['uid'] )) {
        $return ['status'] = - 1;
        return $return;
    }
    $return ['member'] = $member;
    $return ['status'] = 1;
    if ($member ['_inarchive']) {
        C::t ( 'common_member_archive' )->move_to_master ( $member ['uid'] );
    }
    if ($member ['email'] != $return ['ucresult'] ['email']) {
        C::t ( 'common_member' )->update ( $return ['ucresult'] ['uid'], array (
                'email' => $return ['ucresult'] ['email'] 
        ) );
    }
    
    return $return;
}

 

4,修改 class_member.php 添加支持 Cas登录支持

 

修改 OnLogin 方法

function on_login() {
        global $_G;
        if ($_G ['uid']) {
            $referer = dreferer ();
            $ucsynlogin = $this->setting ['allowsynlogin'] ? uc_user_synlogin ( $_G ['uid'] ) : '';
            $param = array (
                    'username' => $_G ['member'] ['username'],
                    'usergroup' => $_G ['group'] ['grouptitle'],
                    'uid' => $_G ['member'] ['uid'] 
            );
            showmessage ( 'login_succeed', $referer ? $referer : './', $param, array (
                    'showdialog' => 1,
                    'locationtime' => true,
                    'extrajs' => $ucsynlogin 
            ) );
        }
        
        list ( $seccodecheck ) = seccheck ( 'login' );
        if (! empty ( $_GET ['auth'] )) {
            $dauth = authcode ( $_GET ['auth'], 'DECODE', $_G ['config'] ['security'] ['authkey'] );
            list ( , , , $secchecklogin2 ) = explode ( "\t", $dauth );
            if ($secchecklogin2) {
                $seccodecheck = true;
            }
        }
        $seccodestatus = ! empty ( $_GET ['lssubmit'] ) ? false : $seccodecheck;
        $invite = getinvite ();
        
        // if(!submitcheck('loginsubmit', 1, $seccodestatus)) {
        if (1 == 2) {
            $auth = '';
            $username = ! empty ( $_G ['cookie'] ['loginuser'] ) ? dhtmlspecialchars ( $_G ['cookie'] ['loginuser'] ) : '';
            
            if (! empty ( $_GET ['auth'] )) {
                list ( $username, $password, $questionexist ) = explode ( "\t", authcode ( $_GET ['auth'], 'DECODE', $_G ['config'] ['security'] ['authkey'] ) );
                $username = dhtmlspecialchars ( $username );
                $auth = dhtmlspecialchars ( $_GET ['auth'] );
            }
            
            $cookietimecheck = ! empty ( $_G ['cookie'] ['cookietime'] ) || ! empty ( $_GET ['cookietime'] ) ? 'checked="checked"' : '';
            
            if ($seccodecheck) {
                $seccode = random ( 6, 1 ) + $seccode {0} * 1000000;
            }
            
            if ($this->extrafile && file_exists ( $this->extrafile )) {
                require_once $this->extrafile;
            }
            
            $navtitle = lang ( 'core', 'title_login' );
            include template ( $this->template );
        } else {
            
            if (! empty ( $_GET ['auth'] )) {
                list ( $_GET ['username'], $_GET ['password'] ) = daddslashes ( explode ( "\t", authcode ( $_GET ['auth'], 'DECODE', $_G ['config'] ['security'] ['authkey'] ) ) );
            }
            
            $loginhash = ! empty ( $_GET ['loginhash'] ) && preg_match ( '/^\w+$/', $_GET ['loginhash'] ) ? $_GET ['loginhash'] : '';
            
            if (! ($_G ['member_loginperm'] = logincheck ( $_GET ['username'] ))) {
                captcha::report ( $_G ['clientip'] );
                showmessage ( 'login_strike' );
            }
            if ($_GET ['fastloginfield']) {
                $_GET ['loginfield'] = $_GET ['fastloginfield'];
            }
            $_G ['uid'] = $_G ['member'] ['uid'] = 0;
            $_G ['username'] = $_G ['member'] ['username'] = $_G ['member'] ['password'] = '';
            
            
            phpCAS::$_PHPCAS_CLIENT->setNoClearTicketsFromUrl ();
            $auth1 = phpCAS::isAuthenticated ();
            
            $username='';
            if ($auth1) {
                $username = phpCAS::getUser ();
            } else {
                phpCAS::forceAuthentication ();
//                 showmessage ( '尚未登录,<a href="" onclick="return gocas();">前去登录</a>' );
                 
            }
 
         
            $password = '';
            $email = phpCAS::getAttribute('Email');
            $uid = phpCAS::getAttribute('Uid');
            // $result = userlogin($_GET['username'], $_GET['password'], $_GET['questionid'], $_GET['answer'], $this->setting['autoidselect'] ? 'auto' : $_GET['loginfield'], $_G['clientip']);
            $result = userloginCas ( $username, $password, $email, $uid );
            $uid = $result ['ucresult'] ['uid'];
            
            if (! empty ( $_GET ['lssubmit'] ) && ($result ['ucresult'] ['uid'] == - 3 || $seccodecheck)) {
                $_GET ['username'] = $result ['ucresult'] ['username'];
                $this->logging_more ( $result ['ucresult'] ['uid'] == - 3 );
            }
            
            if ($result ['status'] == - 1) {
                if (! $this->setting ['fastactivation']) {
                    $auth = authcode ( $result ['ucresult'] ['username'] . "\t" . FORMHASH, 'ENCODE' );
                    showmessage ( 'location_activation', 'member.php?mod=' . $this->setting ['regname'] . '&action=activation&auth=' . rawurlencode ( $auth ) . '&referer=' . rawurlencode ( dreferer () ), array (), array (
                            'location' => true 
                    ) );
                } else {
                    $init_arr = explode ( ',', $this->setting ['initcredits'] );
                    $groupid = $this->setting ['regverify'] ? 8 : $this->setting ['newusergroupid'];
                    
                    C::t ( 'common_member' )->insert ( $uid, $result ['ucresult'] ['username'], md5 ( random ( 10 ) ), $result ['ucresult'] ['email'], $_G ['clientip'], $groupid, $init_arr );
                    $result ['member'] = getuserbyuid ( $uid );
                    $result ['status'] = 1;
                }
            }
            
            if ($result ['status'] > 0) {
                
                if ($this->extrafile && file_exists ( $this->extrafile )) {
                    require_once $this->extrafile;
                }
                
                setloginstatus ( $result ['member'], $_GET ['cookietime'] ? 2592000 : 0 );
                checkfollowfeed ();
                if ($_G ['group'] ['forcelogin']) {
                    if ($_G ['group'] ['forcelogin'] == 1) {
                        clearcookies ();
                        showmessage ( 'location_login_force_qq' );
                    } elseif ($_G ['group'] ['forcelogin'] == 2 && $_GET ['loginfield'] != 'email') {
                        clearcookies ();
                        showmessage ( 'location_login_force_mail' );
                    }
                }
                
                if ($_G ['member'] ['lastip'] && $_G ['member'] ['lastvisit']) {
                    dsetcookie ( 'lip', $_G ['member'] ['lastip'] . ',' . $_G ['member'] ['lastvisit'] );
                }
                C::t ( 'common_member_status' )->update ( $_G ['uid'], array (
                        'lastip' => $_G ['clientip'],
                        'port' => $_G ['remoteport'],
                        'lastvisit' => TIMESTAMP,
                        'lastactivity' => TIMESTAMP 
                ) );
                $ucsynlogin = $this->setting ['allowsynlogin'] ? uc_user_synlogin ( $_G ['uid'] ) : '';
                
                $pwold = false;
                if ($this->setting ['strongpw'] && ! $this->setting ['pwdsafety']) {
                    if (in_array ( 1, $this->setting ['strongpw'] ) && ! preg_match ( "/\d+/", $_GET ['password'] )) {
                        $pwold = true;
                    }
                    if (in_array ( 2, $this->setting ['strongpw'] ) && ! preg_match ( "/[a-z]+/", $_GET ['password'] )) {
                        $pwold = true;
                    }
                    if (in_array ( 3, $this->setting ['strongpw'] ) && ! preg_match ( "/[A-Z]+/", $_GET ['password'] )) {
                        $pwold = true;
                    }
                    if (in_array ( 4, $this->setting ['strongpw'] ) && ! preg_match ( "/[^a-zA-z0-9]+/", $_GET ['password'] )) {
                        $pwold = true;
                    }
                }
                
                if ($_G ['member'] ['adminid'] != 1) {
                    if ($this->setting ['accountguard'] ['loginoutofdate'] && $_G ['member'] ['lastvisit'] && TIMESTAMP - $_G ['member'] ['lastvisit'] > 90 * 86400) {
                        C::t ( 'common_member' )->update ( $_G ['uid'], array (
                                'freeze' => 2 
                        ) );
                        C::t ( 'common_member_validate' )->insert ( array (
                                'uid' => $_G ['uid'],
                                'submitdate' => TIMESTAMP,
                                'moddate' => 0,
                                'admin' => '',
                                'submittimes' => 1,
                                'status' => 0,
                                'message' => '',
                                'remark' => '' 
                        ), false, true );
                        manage_addnotify ( 'verifyuser' );
                        showmessage ( 'location_login_outofdate', 'home.php?mod=spacecp&ac=profile&op=password&resend=1', array (
                                'type' => 1 
                        ), array (
                                'showdialog' => true,
                                'striptags' => false,
                                'locationtime' => true 
                        ) );
                    }
                    
                    if ($this->setting ['accountguard'] ['loginpwcheck'] && $pwold) {
                        $freeze = $pwold;
                        if ($this->setting ['accountguard'] ['loginpwcheck'] == 2 && $freeze) {
                            C::t ( 'common_member' )->update ( $_G ['uid'], array (
                                    'freeze' => 1 
                            ) );
                        }
                    }
                }
                
                $seccheckrule = & $_G ['setting'] ['seccodedata'] ['rule'] ['login'];
                if ($seccheckrule ['allow'] == 2) {
                    if ($seccheckrule ['nolocal']) {
                        require_once libfile ( 'function/misc' );
                        $lastipConvert = process_ipnotice ( convertip ( $_G ['member'] ['lastip'] ) );
                        $nowipConvert = process_ipnotice ( convertip ( $_G ['clientip'] ) );
                        if ($lastipConvert != $nowipConvert && stripos ( $lastipConvert, $nowipConvert ) == false && stripos ( $nowipConvert, $lastipConvert ) == false) {
                            $seccodecheck = true;
                        }
                    }
                    if (! $seccodecheck && $seccheckrule ['pwsimple'] && $pwold) {
                        $seccodecheck = true;
                    }
                    if (! $seccodecheck && $seccheckrule ['outofday'] && $_G ['member'] ['lastvisit'] && TIMESTAMP - $_G ['member'] ['lastvisit'] > $seccheckrule ['outofday'] * 86400) {
                        $seccodecheck = true;
                    }
                    if (! $seccodecheck && $_G ['member_loginperm'] < 4) {
                        $seccodecheck = true;
                    }
                    if (! $seccodecheck && $seccheckrule ['numiptry']) {
                        $seccodecheck = failedipcheck ( $seccheckrule ['numiptry'], $seccheckrule ['timeiptry'] );
                    }
                    if ($seccodecheck && ! $secchecklogin2) {
                        clearcookies ();
                        $auth = authcode ( $_GET ['username'] . "\t" . $_GET ['password'] . "\t" . ($_GET ['questionid'] ? 1 : 0) . "\t1", 'ENCODE', $_G ['config'] ['security'] ['authkey'] );
                        $location = 'member.php?mod=logging&action=login&auth=' . rawurlencode ( $auth ) . '&referer=' . rawurlencode ( dreferer () ) . (! empty ( $_GET ['cookietime'] ) ? '&cookietime=1' : '');
                        if (defined ( 'IN_MOBILE' )) {
                            showmessage ( 'login_seccheck2', $location );
                        } else {
                            $js = '<script type="text/javascript">location.href=\'' . $location . '\'</script>';
                            showmessage ( 'login_seccheck2', '', array (
                                    'type' => 1 
                            ), array (
                                    'extrajs' => $js 
                            ) );
                        }
                    }
                }
                
                if ($invite ['id']) {
                    $result = C::t ( 'common_invite' )->count_by_uid_fuid ( $invite ['uid'], $uid );
                    if (! $result) {
                        C::t ( 'common_invite' )->update ( $invite ['id'], array (
                                'fuid' => $uid,
                                'fusername' => $_G ['username'] 
                        ) );
                        updatestat ( 'invite' );
                    } else {
                        $invite = array ();
                    }
                }
                if ($invite ['uid']) {
                    require_once libfile ( 'function/friend' );
                    friend_make ( $invite ['uid'], $invite ['username'], false );
                    dsetcookie ( 'invite_auth', '' );
                    if ($invite ['appid']) {
                        updatestat ( 'appinvite' );
                    }
                }
                
                $param = array (
                        'username' => $result ['ucresult'] ['username'],
                        'usergroup' => $_G ['group'] ['grouptitle'],
                        'uid' => $_G ['member'] ['uid'],
                        'groupid' => $_G ['groupid'],
                        'syn' => $ucsynlogin ? 1 : 0 
                );
                
                $extra = array (
                        'showdialog' => true,
                        'locationtime' => true,
                        'extrajs' => $ucsynlogin 
                );
                
                if (! $freeze || ! $this->setting ['accountguard'] ['loginpwcheck']) {
                    $loginmessage = $_G ['groupid'] == 8 ? 'login_succeed_inactive_member' : 'login_succeed';
                    $location = $invite || $_G ['groupid'] == 8 ? 'home.php?mod=space&do=home' : dreferer ();
                } else {
                    $loginmessage = 'login_succeed_password_change';
                    $location = 'home.php?mod=spacecp&ac=profile&op=password';
                    $_GET ['lssubmit'] = 0;
                }
                if (empty ( $_GET ['handlekey'] ) || ! empty ( $_GET ['lssubmit'] )) {
                    if (defined ( 'IN_MOBILE' )) {
                        showmessage ( $loginmessage, $location, $param, array (
                                'location' => true 
                        ) );
                    } else {
                        if (! empty ( $_GET ['lssubmit'] )) {
                            if (! $ucsynlogin) {
                                $extra ['location'] = true;
                            }
                            showmessage ( $loginmessage, $location, $param, $extra );
                        } else {
                            $href = str_replace ( "'", "\'", $location );
                            showmessage ( 'location_login_succeed', $location, array (), array (
                                    'showid' => 'succeedmessage',
                                    'extrajs' => '<script type="text/javascript">' . 'setTimeout("window.location.href =\'' . $href . '\';", 3000);' . '$(\'succeedmessage_href\').href = \'' . $href . '\';' . '$(\'main_message\').style.display = \'none\';' . '$(\'main_succeed\').style.display = \'\';' . '$(\'succeedlocation\').innerHTML = \'' . lang ( 'message', $loginmessage, $param ) . '\';</script>' . $ucsynlogin,
                                    'striptags' => false,
                                    'showdialog' => true 
                            ) );
                        }
                    }
                } else {
                    showmessage ( $loginmessage, $location, $param, $extra );
                }
            } else {
                $password = preg_replace ( "/^(.{" . round ( strlen ( $_GET ['password'] ) / 4 ) . "})(.+?)(.{" . round ( strlen ( $_GET ['password'] ) / 6 ) . "})$/s", "\\1***\\3", $_GET ['password'] );
                $errorlog = dhtmlspecialchars ( TIMESTAMP . "\t" . ($result ['ucresult'] ['username'] ? $result ['ucresult'] ['username'] : $_GET ['username']) . "\t" . $password . "\t" . "Ques #" . intval ( $_GET ['questionid'] ) . "\t" . $_G ['clientip'] );
                writelog ( 'illegallog', $errorlog );
                loginfailed ( $_GET ['username'] );
                failedip ();
                $fmsg = $result ['ucresult'] ['uid'] == '-3' ? (empty ( $_GET ['questionid'] ) || $answer == '' ? 'login_question_empty' : 'login_question_invalid') : 'login_invalid';
                if ($_G ['member_loginperm'] > 1) {
                    showmessage ( $fmsg, '', array (
                            'loginperm' => $_G ['member_loginperm'] - 1 
                    ) );
                } elseif ($_G ['member_loginperm'] == - 1) {
                    showmessage ( 'login_password_invalid' );
                } else {
                    showmessage ( 'login_strike' );
                }
            }
        }
    }
    

 

 

修改 on_logout 支持同步退出

function on_logout() {
        global $_G;
        
        $ucsynlogout = $this->setting ['allowsynlogin'] ? uc_user_synlogout () : '';
        
        if ($_GET ['formhash'] != $_G ['formhash']) {
            showmessage ( 'logout_succeed', dreferer (), array (
                    'formhash' => FORMHASH,
                    'ucsynlogout' => $ucsynlogout,
                    'referer' => rawurlencode ( dreferer () ) 
            ) );
        }
        
        clearcookies ();
        $_G ['groupid'] = $_G ['member'] ['groupid'] = 7;
        $_G ['uid'] = $_G ['member'] ['uid'] = 0;
        $_G ['username'] = $_G ['member'] ['username'] = $_G ['member'] ['password'] = '';
        $_G ['setting'] ['styleid'] = $this->setting ['styleid'];
        
        if (defined ( 'IN_MOBILE' )) {
            showmessage ( 'location_logout_succeed_mobile', dreferer (), array (
                    'formhash' => FORMHASH,
                    'referer' => rawurlencode ( dreferer () ) 
            ) );
        } else {
            // 退出
            $service =  dreferer ()  ;
            phpCAS::logoutWithRedirectService ( $service );
            // 后面这个showmessage提示实际上已经不会执行了
//             showmessage ( 'logout_succeed', dreferer (), array (
//                     'formhash' => FORMHASH,
//                     'ucsynlogout' => $ucsynlogout,
//                     'referer' => rawurlencode ( dreferer () ) 
//             ) );
        }
    }
}

 

当然,最后把登录改成 到登录界面去登录的方式,这样才会生效,这其实是最简单的方法了。

如下图进行设置

 

image

 

CAS 结构 如下:

 

image

 

 

其中CAS 包我也做了小小的修改,但这个与主要业务无关,就不传了。

 

最后,我的版本是 Discuz! X3.1 Release 20131011 。

 

从 其它系统跳转到要检测是否已经登录,可以作用JS的方法判断CAS Server是否已经登录,如果已经登录,跳转到登录然后再返回

或使得JS方式从后台调用 CAS的方法进行登录,然后使用Ajax的方式,更新界面。

 

我的CASServer C# 版本 是自己的写的,但我基本上遵循的 CAS 2.0 的协议,所以对于Java版本CAS也差不多。相应代码可参见的GitHub上的代码。

posted @ 2013-12-04 15:25  张保维  阅读(3506)  评论(25编辑  收藏  举报