实现持久登录,即用户在登录时,勾选了"记住我"之后,无论是否关闭浏览器,只要不退出登录,在指定的时间内始终保持登录状态(缺点是在另一台电脑上登录过后,之前那台电脑就不能继续保持登录状态)。
首先,持久登陆使用 cookie 实现,但是 cookie 中不能保存用户密码这样重要的信息,即使加密过。解决方案是在用户登录表中新建3个字段identifier:第二身份标识,token:永久登录标识,timeout:永久登录超时时间。
+------------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+-------------+------+-----+---------+----------------+ | uid | int(11) | NO | PRI | NULL | auto_increment | | uname | varchar(20) | YES | | NULL | | | upwd | varchar(20) | YES | | NULL | | | uflag | int(11) | YES | | NULL | | | identifier | varchar(32) | YES | | NULL | | | token | varchar(32) | YES | | NULL | | | timeout | int(11) | YES | | NULL | | +------------+-------------+------+-----+---------+----------------+
在用户勾选了"记住我"登录时,应该生成一个唯一的 identifier,一个唯一的 token,并且设置一个过期时间 timeout,把两个代表身份的值写入cookie,设置 cookie 过期时间为 timeout,例如:setcookie('auth',"$identifier:$token",$timeout); 同时把三个值插入数据表;当用户再一次访问网站时,首先判断 cookie 中是否含有 auth,如果含有,则去数据库中进行身份比对(identifier 和 token),比对成功时,把用户信息写入 session,同时用户保持登录状态。
控制器 TestController.class.php
代码:
<?php namespace Test\Controller; use Think\Controller; class TestController extends Controller {public function login(){//判断是否永久登录$this->checkLong();//已经登录则跳转至个人中心if(isset($_SESSION['username'])){$this->redirect('Test/ucenter');}else{//判断是否存在cookieif(isset($_COOKIE['username'])){$this->assign('username',$_COOKIE['username']);}//显示注册页$this->display("test");}}//显示验证码public function verifyImg(){$verify = new \Think\Verify();//$verify->useZh = true; //使用中文验证码$verify->length = 4; $verify->entry();}//验证登录public function check(){$verify = new \Think\Verify();if($verify->check(I("yzm"))){//判断用户名密码$user = new \Test\Model\TestModel();$res = $user->checkName(I("username"),I("pwd"));if($res === false){echo "用户名或密码错误";}else{//用户信息存入sessionsession("username",$res['uname']);session("id",$res['uid']);//如果用户勾选了"记住我",则保持持久登陆if(I("remember")){$salt = $this->random_str(16);//第二分身标识$identifier = md5($salt . md5(I("username") . $salt));//永久登录标识$token = md5(uniqid(rand(), true));//永久登录超时时间(1周)$timeout = time()+3600*24*7;//存入cookiesetcookie('auth',"$identifier:$token",$timeout);$user->saveRemember($res['uid'],$identifier,$token,$timeout);}//把用户名存入cookie,退出登录后在表单保存用户名信息setcookie('username',I('username'),time()+3600*24);//跳转至会员中心$this->redirect('Test/ucenter');}}else{echo "输入错误";}} //测试strstr函数public function strstrtest(){$param = "Think\Verify";//第三个参数为true,返回'Think';没有第三个参数,返回'\Verify'$name = strstr($param,'\\',true);echo $name;}//用户中心public function ucenter(){//判断是否永久登录$this->checkLong();$this->assign("session",$_SESSION);$this->display("ucenter");}//退出登录public function loginout(){session(null);setcookie('auth', '', time()-1);$this->redirect("Test/login");}//生成随机数,用于生成saltpublic function random_str($length){//生成一个包含 大写英文字母, 小写英文字母, 数字 的数组$arr = array_merge(range(0, 9), range('a', 'z'), range('A', 'Z'));$str = '';$arr_len = count($arr);for ($i = 0; $i < $length; $i++){$rand = mt_rand(0, $arr_len-1);$str.=$arr[$rand];}return $str;}//判断是否持久登录public function checkLong(){$check = new \Test\Model\TestModel();$is_long = $check->checkRemember();if($is_long === false){}else{session("username",$is_long['uname']);session("id",$is_long['uid']);}} }
模型 TestModel.class.php
<?php namespace Test\Model; use Think\Model; class TestModel extends Model{//验证登录信息public function checkName($name,$pwd){$admin = M("admin");$info = $admin->getByUname($name);if($info != null){//验证密码if($info['upwd'] == $pwd){return $info;}else{return false;}}else{return false;}}//当用户勾选"记住我"public function saveRemember($uid,$identifier,$token,$timeout){$admin = M("admin");$data['identifier'] = $identifier;$data['token'] = $token;$data['timeout'] = $timeout;$where = " uid = ".$uid;$res = $admin->data($data)->where($where)->save();return $res;}//验证用户是否永久登录(记住我)public function checkRemember(){$arr = array();$now = time();list($identifier,$token) = explode(':',$_COOKIE['auth']);if (ctype_alnum($identifier) && ctype_alnum($token)){$arr['identifier'] = $identifier;$arr['token'] = $token;}else{return false;}$admin = M("admin");$info = $admin->getByidentifier($arr['identifier']);if($info != null){if($arr['token'] != $info['token']){return false;}else if($now > $info['timeout']){return false;}else{return $info;}}else{return false;}} }
视图 登录页 test.html
<DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Document</title> </head> <body> <form action="__CONTROLLER__/check" method="post"> <if condition="$username neq null"><input type="text" name="username" placeholder="用户名" value="{$username}"><br> <else /><input type="text" name="username" placeholder="用户名"><br> </if> <input type="password" name="pwd" placeholder="密码"><br> <input type="text" name="yzm" placeholder="验证码"><img src="__CONTROLLER__/verifyImg" onClick="this.src=this.src+'?'+Math.random()"><br> <input type="checkbox" name="remember" id="remember"><label for="remember">记住我</label> <input type="submit" value="提交"> </form> </body> </html>
视图 个人中心 ucenter.html
<DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Documenttitle> </head> <body><if condition="$session['username'] neq null"><i>{$session.username},</i><else /><i>游客,</i></if>欢迎您<br><a href="__CONTROLLER__/loginout">退出登录</a> </body> </html>