DISCUZ 自动登录功能解析

来源:互联网 发布:防伪底纹制作软件下载 编辑:程序博客网 时间:2024/05/17 00:04

这里以DISCUZ X2.5 为例, X3和X2.5几乎一样

自动登录操作时,系统做了哪些操作

联系作者:addon.discuz.com/?@12744.developer     做企业网站:www.dianzana.com

选中自动登录,查看网页代码如下:

<form method="post" autocomplete="off" id="lsform" action="member.php?mod=logging&action=login&loginsubmit=yes&infloat=yes&lssubmit=yes" onsubmit="return lsSubmit();"><div class="fastlg cl"><span id="return_ls" style="display:none"></span><div class="y pns"><table cellspacing="0" cellpadding="0"><tbody><tr><td><span class="ftid"><select name="fastloginfield" id="ls_fastloginfield" width="40" tabindex="900" selecti="0" style="display: none;"><option value="username"></option></select><a href="javascript:;" id="ls_fastloginfield_ctrl" style="width:40px" tabindex="900">用户名</a></span><script type="text/javascript">simulateSelect('ls_fastloginfield')</script></td><td><input type="text" name="username" id="ls_username" autocomplete="off" class="px vm" tabindex="901"></td><td class="fastlg_l"><label for="ls_cookietime"><input type="checkbox" name="cookietime" id="ls_cookietime" class="pc" value="2592000" tabindex="903">自动登录</label></td><td> <a href="javascript:;" onclick="showWindow('login', 'member.php?mod=logging&action=login&viewlostpw=1')">找回密码</a></td></tr><tr><td><label for="ls_password" class="z psw_w">密码</label></td><td><input type="password" name="password" id="ls_password" class="px vm" autocomplete="off" tabindex="902"></td><td class="fastlg_l"><button type="submit" class="pn vm" tabindex="904" style="width: 75px;"><em>登录</em></button></td><td> <a href="member.php?mod=register" class="xi2 xw1">立即注册</a></td></tr></tbody></table><input type="hidden" name="quickforward" value="yes"><input type="hidden" name="handlekey" value="ls"></div></div></form>

很明显,访问的地址是:member.php?mod=logging&action=login&loginsubmit=yes&infloat=yes&lssubmit=yes, 自动登录复选框的name="cookietime"

依访问路径找到文件:

x25/member.php

x25/source/module/member/member_logging.php  其中 new logging_ctl() 找到

x25/source/class/class_member.php  下面是on_login()方法

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));}$from_connect = $this->setting['connect']['allow'] && !empty($_GET['from']) ? 1 : 0;$seccodecheck = $from_connect ? false : $this->setting['seccodestatus'] & 2;$seccodestatus = !empty($_GET['lssubmit']) ? false : $seccodecheck;$invite = getinvite();if(!submitcheck('loginsubmit', 1, $seccodestatus)) {$auth = '';$username = !empty($_G['cookie']['loginuser']) ? dhtmlspecialchars($_G['cookie']['loginuser']) : '';if(!empty($_GET['auth'])) {list($username, $password, $questionexist) = explode("\t", authcode($_GET['auth'], 'DECODE'));$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')));}if(!($_G['member_loginperm'] = logincheck($_GET['username']))) {showmessage('login_strike');}if($_GET['fastloginfield']) {$_GET['loginfield'] = $_GET['fastloginfield'];}$_G['uid'] = $_G['member']['uid'] = 0;$_G['username'] = $_G['member']['username'] = $_G['member']['password'] = '';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']);$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();C::t('common_member_status')->update($_G['uid'], array('lastip' => $_G['clientip'], 'lastvisit' =>TIMESTAMP, 'lastactivity' => TIMESTAMP));$ucsynlogin = $this->setting['allowsynlogin'] ? uc_user_synlogin($_G['uid']) : '';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);$loginmessage = $_G['groupid'] == 8 ? 'login_succeed_inactive_member' : 'login_succeed';$location = $invite || $_G['groupid'] == 8 ? 'home.php?mod=space&do=home' : dreferer();if(empty($_GET['handlekey']) || !empty($_GET['lssubmit'])) {if(defined('IN_MOBILE')) {showmessage('location_login_succeed_mobile', $location, array('username' => $result['ucresult']['username']), 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']);$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');}}}}

很明显,表单未提交执行的是:

if(!submitcheck('loginsubmit', 1, $seccodestatus)) {}

这里我们是登录操作,所以只需要看else部分,else部分其中有如下代码:

if($result['status'] > 0) {if($this->extrafile && file_exists($this->extrafile)) {require_once $this->extrafile;}setloginstatus($result['member'], $_GET['cookietime'] ? 2592000 : 0);checkfollowfeed();..........}

$result['status']>0,肯定是登录成功的,现在来看函数 setloginstatus($result['member'], $_GET['cookietime'] ? 2592000 : 0);

下面找到此函数文件 source/function/function_member.php

function setloginstatus($member, $cookietime) {global $_G;$_G['uid'] = intval($member['uid']);$_G['username'] = $member['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);dsetcookie('loginuser');dsetcookie('activationauth');dsetcookie('pmnum');include_once libfile('function/stat');updatestat('login', 1);if(defined('IN_MOBILE')) {updatestat('mobilelogin', 1);}if($_G['setting']['connect']['allow'] && $_G['member']['conisbind']) {updatestat('connectlogin', 1);}$rule = updatecreditbyaction('daylogin', $_G['uid']);if(!$rule['updatecredit']) {checkusergroup($_G['uid']);}}

其中代码  dsetcookie('auth', authcode("{$member['password']}\t{$member['uid']}", 'ENCODE'), $cookietime, 1, true);  把auth保存到cookie中,cookie有效时间是2592000秒,即30天

登录成功后打开Chrome浏览器本地cookie


今天是2014年4月23日,可看到cookie中有3个值的到期时间是2014年5月23日,已经圈红,可能与我们的自动登录有关,其中ZRcL_2132_auth应该就是我们刚才保存的auth


系统是如何实现下次自动登录的

自动登录肯定是在系统初始化时操作的,经过搜索这几个cookie名称,我们定位到: x25/source/class/discuz/discuz_application.php   此文件是系统核心文件,在入口处执行,下面是方法  _init_input() 中的代码:

if(empty($this->var['cookie']['saltkey'])) {$this->var['cookie']['saltkey'] = random(8);dsetcookie('saltkey', $this->var['cookie']['saltkey'], 86400 * 30, 1, 1);}$this->var['authkey'] = md5($this->var['config']['security']['authkey'].$this->var['cookie']['saltkey']);

其中 $this->var 就是全局变量 $_G ,在此文件的 _init_env() 方法中有定义:

$this->var = & $_G;

其实上面的操作就是判断当前是否已经设有cookie saltkey,没有的话随机生成一个,然后保存到cookie中
然后 MD5加密当前的$_config_security_authkey 与 saltkey,保存到$_G['authkey']中
下面我们看$_G['authkey']是干什么的,查看 x25/source/function/function_core.php 中的authcode()函数

function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {$ckey_length = 4;$key = md5($key != '' ? $key : getglobal('authkey'));$keya = md5(substr($key, 0, 16));$keyb = md5(substr($key, 16, 16));$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';$cryptkey = $keya.md5($keya.$keyc);$key_length = strlen($cryptkey);$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;$string_length = strlen($string);$result = '';$box = range(0, 255);$rndkey = array();for($i = 0; $i <= 255; $i++) {$rndkey[$i] = ord($cryptkey[$i % $key_length]);}for($j = $i = 0; $i < 256; $i++) {$j = ($j + $box[$i] + $rndkey[$i]) % 256;$tmp = $box[$i];$box[$i] = $box[$j];$box[$j] = $tmp;}for($a = $j = $i = 0; $i < $string_length; $i++) {$a = ($a + 1) % 256;$j = ($j + $box[$a]) % 256;$tmp = $box[$a];$box[$a] = $box[$j];$box[$j] = $tmp;$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));}if($operation == 'DECODE') {if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {return substr($result, 26);} else {return '';}} else {return $keyc.str_replace('=', '', base64_encode($result));}}

注意其中的  $key = md5($key != '' ? $key : getglobal('authkey'));  原来authkey是默认的加密密钥, 看来之前生成的 auth 是和系统配置文件$_config_security_authkey 及随机值 saltkey 相关的,那么如果没有saltkey,是无法解密auth的,也就无法实现自动登录了。

下面查看 discuz_application.php 中的 _init_user() 方法,其中有如下代码:

if($auth = getglobal('auth', 'cookie')) {$auth = daddslashes(explode("\t", authcode($auth, 'DECODE')));}list($discuz_pw, $discuz_uid) = empty($auth) || count($auth) < 2 ? array('', '') : $auth;if($discuz_uid) {$user = getuserbyuid($discuz_uid, 1);}

首先获取当前COOKIE中的auth,    $auth = getglotal('auth', 'cookie')  ,如果有,则执行下面操作:

$auth = daddslashes(explode("\t", authcode($auth, 'DECODE')));

解密出auth,然后就直接获取 password 和 uid 了

list($discuz_pw, $discuz_uid) = empty($auth) || count($auth) < 2 ? array('', '') : $auth;

至此结束!!!!!!!!

0 0
原创粉丝点击