由于工作的需要,所以开始分析phpwind9.0论坛的部分功能的处理机制,这一节来分析登陆机制。
首先当用户点击进入登陆页面后:(这里不讨论快速登陆和直接在页头登陆的情况,原理基本一致)
进入该类调用run成员函数进入页面初始化。该类继承自PwBaseController这个基础类,这基础类中关于风格会有一些处理。接着回到LoginController类,当用户输入了用户名和密码后,点击提交,调用该类的dorunAction()成员函数,大致流程就是判定验证码以及用户名和密码是否正确,然后形成一个整站的该用户标识,接着进入正常的访问界面,该函数具体如下:
[php] view plaincopy
public function dorunAction() {
$userForm = $this->_getLoginForm();
/* [验证验证码是否正确] */
if ($this->_showVerify()) {
$veryfy = $this->_getVerifyService();
if ($veryfy->checkVerify($userForm['code']) !== true) {
$this->showError('USER:verifycode.error');
}
}
$question = $userForm['question'];
if ($question == -4) {
$question = $this->getInput('myquestion', 'post');
}
/* [验证用户名和密码是否正确] */
$login = new PwLoginService();
$this->runHook('c_login_dorun', $login);
$isSuccess = $login->login($userForm['username'], $userForm['password'], $this->getRequest()->getClientIp(), $question, $userForm['answer']);
if ($isSuccess instanceof PwError) {
$this->showError($isSuccess->getError());
}
$config = Wekit::C('site');
if ($config['windid'] != 'local') {
$localUser = $this->_getUserDs()->getUserByUid($isSuccess['uid'], PwUser::FETCH_MAIN);
if ($localUser['username'] && $userForm['username'] != $localUser['username']) $this->showError('USER:user.syn.error');
}
Wind::import('SRV:user.srv.PwRegisterService');
$registerService = new PwRegisterService();
$info = $registerService->sysUser($isSuccess['uid']);
if (!$info) $this->showError('USER:user.syn.error');
$identity = PwLoginService::createLoginIdentify($info);
$identity = base64_encode($identity . '|' . $this->getInput('backurl') . '|' . $userForm['rememberme']);
/* [是否需要设置安全问题] */
/* @var $userService PwUserService */
$userService = Wekit::load('user.srv.PwUserService');
//解决浏览器记录用户帐号和密码问题
if ($isSuccess['safecv'] && !$question) {
$this->addMessage(true, 'qaE');
$this->showError('USER:verify.question.empty');
}
//该帐号必须设置安全问题
if (empty($isSuccess['safecv']) && $userService->mustSettingSafeQuestion($info['uid'])) {
$this->addMessage(array('url' => WindUrlHelper::createUrl('u/login/setquestion', array('v' => 1, '_statu' => $identity))), 'check');
}
$this->showMessage('', 'u/login/welcome?_statu=' . $identity);
}
第2行代码$userForm = $this->_getLoginForm()是获取表单提交的具体数据,该函数的具体内容在该类中。接着判断验证码和安全问题,然后就是判断用户名和密码是否正确,关键就是其中的这段代码了:
[php] view plaincopy
$login = new PwLoginService();
$this->runHook('c_login_dorun', $login);
$isSuccess = $login->login($userForm['username'], $userForm['password'], $this->getRequest()->getClientIp(), $question, $userForm['answer']);
这里注意 该类的一些成员函数,其中包括login,接下来对登陆模块进行一些hook注册处理,然后进入login实质性的处理部分:
[php] view plaincopy
$isSuccess = $login->login($userForm['username'], $userForm['password'], $this->getRequest()->getClientIp(), $question, $userForm['answer']);
调用PwLoginService类的login成员函数:(用户登陆)
[php] view plaincopy
public function login($username, $password, $ip, $safeQuestion = null, $safeAnswer = '') {
$checkQ = !is_null($safeQuestion) ? true : false;
Wind::import("SRV:user.srv.PwTryPwdBp");
$pwdBp = new PwTryPwdBp();
$info = $pwdBp->auth($username, $password, $ip, $checkQ, $safeQuestion, $safeAnswer);
if ($info instanceof PwError) return $info;
if (($result = $this->runWithVerified('afterLogin', $info)) instanceof PwError) return $result;
return $info;
}
根据phpwind官方手册上的说明
(http://wiki.open.phpwind.com/index.php?title=%E7%B1%BB%E5%BA%93%E5%8A%A0%E8%BD%BD%E6%96%B9%E5%BC%8F)这里的
Wind::import("SRV:user.srv.PwTryPwdBp");即将导入的就是
该类(在该类的第一行代码是导入的有关登陆信息的有效性检查的类),接着我们回到PwLoginService类的login成员函数,看到该行代码:
$info=$pwdBp->auth($username,$password,$ip,$checkQ,$safeQuestion,$safeAnswer);
我们进入PwTryPwdBp类:
[php] view plaincopy
public function auth($username, $password, $ip = '', $checkQ = false, $safeQuestion = '', $safeAnswer = '') {
…
//用户名登录
if ($r[0] == -14 && in_array(3, $this->loginConfig['ways'])) {
$r = $this->_getWindid()->login($username, $password, 2, $checkQ, $safeQuestion, $safeAnswer);
}
return $this->checkVerifyResult($r[0], $r[1]);
}
看到代码:$this->_getWindid(),该成员函数将会通过调用特定的userApi来获取当前用户的信息:
protected function _getWindid() {
return WindidApi::api('user');
}
进入类中经分析,该类
requireWINDID_BOOT.'bootstrap.php'文件,然后调用全局的配置文件:
,得到WINDID_CONNECT的方式为db,接着我们继续查看
类的相关代码:
if (WINDID_CONNECT == 'db') {
$class = Wind::import('WINDID:api.local.'.$class);
$cls[$class] =new$class();
}
而我们通过之前提到的配置文件可知,WINDID对应的就是/src/windid这个目录,于是最终就是调用了
该类,而该类的login成员函数的代码如下:
[php] view plaincopy
public function login($userid, $password, $type = 2, $ifcheck = false, $question = '', $answer = '') {
return $this->_getUserService()->login($userid, $password, $type, $ifcheck, $question, $answer);
}
代码中_getUserService()对应的是该类中的成员函数:
private function _getUserService() {
return Wekit::load('WSRV:user.srv.WindidUserService');
}
WSRV对应的是/src/windid/service目录,这样就是载入
/src/windid/service/user/srv/下的WindidUserService类,然后我们回到之前的代码(即PwTryPwdBp类的auth成员函数的
$r = $this->_getWindid()->login这个代码):我们已经分析完了
$this->_getWindid()这一部分,接着就是调用这一部分返回的结果
(即WindidUserService类)的login函数:
[php] view plaincopy
public function login($userid, $password, $type = 2, $ifcheck = false, $question = '', $answer = '') {
$user = array();
$ds = $this->_getUserDs();
switch ($type){
case 1:
$user = $ds->getUserByUid($userid, WindidUser::FETCH_MAIN);
break;
case 2:
$user = $ds->getUserByName($userid, WindidUser::FETCH_MAIN);
break;
case 3:
$user = $ds->getUserByEmail($userid, WindidUser::FETCH_MAIN);
break;
}
if (!$user) return array(WindidError::USER_NOT_EXISTS);
if ($ifcheck) {
$safecv = WindidUtility::buildQuestion($question, $answer);
if ($safecv != $user['safecv']) return array(WindidError::SAFECV_ERROR, $user);
}
if (WindidUtility::buildPassword($password, $user['salt']) !== $user['password']) {
return array(WindidError::PASSWORD_ERROR, $user);
}
return array(1, $user);
}
显然我们看到这个函数有一个过程,就是先利用用户名访问数据库获取该用户的相关数据($ds = $this->_getUserDs()以及数据库相关的代码将要访问的文件主要是
/src/windid/service/user目录下的文件,比如数据库就是访问dao文件夹),然后利用用户登陆提交的密码经过一定处理后与我们访问数据库获取到的密码进行对比,然后确认用户登陆成功。
针对代码,来说一下这一行:
[php] view plaincopy
if (WindidUtility::buildPassword($password, $user['salt']) !== $user['password']) {
return array(WindidError::PASSWORD_ERROR, $user);
}
这一行主要调用该类下的
buildPassword成员函数,具体内容为:
[php] view plaincopy
public static function buildPassword($password, $salt) {
return md5(md5($password) . $salt);
}
其参数salt是存放在该用户的salt字段中,对应的具体用户表为pw_windid_user表。
分析完最重要的login函数之后,我们回到最初的需要调用该函数的地方:
类中的login成员函数的代码:
[php] view plaincopy
$r = $this->_getWindid()->login($username, $password, 2, $checkQ, $safeQuestion, $safeAnswer);
该login根据上面的的处理可知:返回的是:
[php] view plaincopy
return array(1, $user);
那么将这个数组返回给$r,接着执行:
[php] view plaincopy
return $this->checkVerifyResult($r[0], $r[1]);
该函数还是在该类中,最终返回的是$r[1]这个数组,也就是用户的所有信息,接着我们回到该类的login函数,继续返回该数组,接着返回最初的,进行登录后的其他处理。
整个登录过程基本就是这样。
本文主要参考了
1.phpwind官方手册:http://wiki.open.phpwind.com/index.php?title=%E9%A6%96%E9%A1%B5
2.Phpwind用户登录机制分析:http://wikimo.net/blogs/330/(这个作用不太大,老版本的,现在新版本流程基本不一样了,不过可以有个了解)
转载请注明出处:http://blog.csdn.net/jayxujia123/article/details/35792649
作者邮箱:[email protected]