discuz 接入 cas

discuz 接入 cas 实现 SSO 的方法。

版本

  • Discuz 3.3
  • Cas 5.x

下载 casPHP 插件

http://developer.jasig.org/cas-clients/php/

我这里用的 1.3.0,下载完后解压拷贝到 discuz 根目录,重命名为 CAS

去除登录输入

修改 template/default/member/login_simple.htm

  • 删除8-29行代码,删除31-32行代码

  • 添加以下代码,支持访问时 force 登录.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 需要 CAS 打开允许 iframe, 否则报错: Refused to display 'URL' in a frame because it set 'X-Frame-Options' to 'DENY'
# cas 配置:cas.httpWebRequest.header.xframe=false
<script type="text/javascript">
(function () {
       var _body = document.body || document.getElementsByTagName('body')[0];
       var iframe = document.createElement('iframe');
       iframe.id = 'logcheck';

       iframe.src = "member.php?"+(("mod=logging&action=loginCheck"));
       iframe.style.display = 'none';
       _body.appendChild(iframe);
   })();
</script>

# TODO 现只能在 CAS 登录后才能登录,需做修改

去除弹框登录

管理中心 -> 界面 -> 去掉浮动窗口(登录)

image

CAS文件夹中创建 CasClientConfig.php

1
2
3
4
5
<?php
define ( 'CAS_SERVER_HOSTNAME', 'cas.com' );
define ( 'CAS_SERVER_PORT', 8080 ); 
define ( 'CAS_SERVER_APP_NAME', "cas" ); 
?>

CAS文件夹中创建 CasClient.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<?php
require_once DISCUZ_ROOT.'./CAS/CasClientConfig.php'; // 注意
require_once DISCUZ_ROOT.'./CAS/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 ();

phpCAS::setNoClearTicketsFromUrl ();
phpCAS::handleLogoutRequests();

?>

source/class/class_core.php第16行加入

1
require_once DISCUZ_ROOT."CAS/CasClient.php";

uc_client/control/user.php

134行注释

1
2
3
4
5
// elseif($user['password'] != md5($passwordmd5.$user['salt'])) {
// $status = -2;
// } elseif($checkques && $user['secques'] != $_ENV['user']->quescrypt($questionid, $answer)) {
// $status = -3;
// }

注释 onsynlogin, onsynlogout, onregister方法

source/function/function_member.php 加入

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 新加的方法,用以支持CAS 登录
function userloginCas($username, $ip = '') {
    $return = array ();
    
    if(!function_exists('uc_user_login')) {
        loaducenter();
    }

    $return['ucresult'] = uc_user_login(addslashes($username), '', 0, 0,'', '', $ip);

    $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;
}

source/class/class_member.php

51行注释并改为

1
2
// if(!submitcheck('loginsubmit', 1, $seccodestatus)) {
if (1 == 2) {

92行 $_G['username'] = $_G['member']['username'] = $_G['member']['password'] = '' 后加入

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
phpCAS::setNoClearTicketsFromUrl ();
// 这里会检测服务器端的退出的通知,就能实现php和其他语言平台间同步登出了  
phpCAS::handleLogoutRequests();  
$username='';
if(phpCAS::isAuthenticated()){  
    $username = phpCAS::getUser ();
} else {
    $service =  $_SERVER['HTTP_REFERER'];
    phpCAS::setServerLoginUrl(phpCAS::getServerLoginURL().urlencode("?service=".$service));

    phpCAS::forceAuthentication ();
}
// if(!$_GET['password'] || $_GET['password'] != addslashes($_GET['password'])) {
// showmessage('profile_passwd_illegal');
// }
// $result = userlogin($_GET['username'], $_GET['password'], $_GET['questionid'], $_GET['answer'], $this->setting['autoidselect'] ? 'auto' : $_GET['loginfield'], $_G['clientip']);
$result = userloginCas($username, $_G['clientip']);

347行 on_logout 方法

1
2
3
4
5
6
7
if(defined('IN_MOBILE')) {
    showmessage('location_logout_succeed_mobile', dreferer(), array('formhash' => FORMHASH, 'referer' => rawurlencode(dreferer())));
} else {
    $service =  $_SERVER['HTTP_REFERER'];
    phpCAS::logoutWithRedirectService ( $service );
// showmessage('logout_succeed', dreferer(), array('formhash' => FORMHASH, 'ucsynlogout' => $ucsynlogout, 'referer' => rawurlencode(dreferer())));
}

386行 on_register方法中

1
2
3
4
5
if(strpos($url_forward, $this->setting['regname']) !== false) {
    $url_forward = 'forum.php';
}
// 修改掉防止当登录成功时无限跳转
$url_forward = 'forum.php';

logging_ctl类中 添加异步登录验证方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
function on_loginCheck(){
    global $_G;
    $username='';
    if(phpCAS::isAuthenticated()){
        $username = phpCAS::getUser ();
    } else {
        phpCAS::setServerLoginUrl(phpCAS::getServerLoginURL());
        phpCAS::forceAuthentication ();
    }
    $result = userloginCas($username, $_G['clientip']);

    if($data = uc_get_user($username)) {
        list($uid, $username, $email) = $data;      //根据用户名获取uid进行登录
    } else {
        dexit();
    }

    if($uid > 0) {
        $member = getuserbyuid($uid, 1);            //根据uid获取用户表pre_common_member中的所有字段

        $_G['uid'] = intval($uid);
        $_G['username'] = $username;
        $_G['adminid'] = $member['adminid'];
        $_G['groupid'] = $member['groupid'];
        $_G['formhash'] = formhash();
        $_G['session']['invisible'] = getuserprofile('invisible');
        $_G['member'] = $member;
        loadcache('usergroup_'.$_G['groupid']);
        C::app()->session->isnew = true;
        C::app()->session->updatesession();

        dsetcookie('auth', authcode("{$member['password']}\t{$member['uid']}", 'ENCODE'), $cookietime, 1, true);        //这里的passwod是pre_common_member表中经过加密后的密码
        dsetcookie('loginuser',$username);
        dsetcookie('activationauth');
        dsetcookie('pmnum');

        dexit('<script type="text/javascript">window.top.location.reload();</script>');
    } else {
        dexit();
    }
}

source/module/member/member_logging.php 添加允许 loginCheck 方法通过

第15行改为 if(!in_array($_GET['action'], array('login', 'logout','loginCheck')))

额外配置,可选

自动https/http

CAS/CAS/Client.php

299行 $this->_server['base_url'] = 'https://' . $this->_getServerHostname(); 改为 $this->_server['base_url'] = ($this->_isHttps() ? 'https':'http').'://'. $this->_getServerHostname();

关闭gateway

CAS/CAS/Client.php

1164行 $this->redirectToCas(true/* gateway */); 改为 $this->redirectToCas(false/* gateway */);