ThinkPHP3.2.2实现持久登录(记住我)功能的方法


Posted in PHP onMay 16, 2016

本文实例讲述了ThinkPHP3.2.2实现持久登录功能的方法。分享给大家供大家参考,具体如下:

实现持久登录,即用户在登录时,勾选了"记住我"之后,无论是否关闭浏览器,只要不退出登录,在指定的时间内始终保持登录状态(缺点是在另一台电脑上登录过后,之前那台电脑就不能继续保持登录状态)。

首先,持久登陆使用 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{
   //判断是否存在cookie
   if(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{
    //用户信息存入session
    session("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;
     //存入cookie
     setcookie('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");
 }
 //生成随机数,用于生成salt
 public 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>
PHP 相关文章推荐
php中关于普通表单多文件上传的处理方法
Mar 25 PHP
php中计算中文字符串长度、截取中文字符串的函数代码
Aug 09 PHP
php中计算程序运行时间的类代码
Nov 03 PHP
php 修改、增加xml结点属性的实现代码
Oct 22 PHP
php中的四舍五入函数代码(floor函数、ceil函数、round与intval)
Jul 14 PHP
php函数与传递参数实例分析
Nov 15 PHP
php基于curl扩展制作跨平台的restfule 接口
May 11 PHP
php生成图片验证码的实例讲解
Aug 03 PHP
浅谈PHP中foreach/in_array的使用
Nov 02 PHP
php上传图片并压缩的实现方法
Dec 22 PHP
PHP实现的分页类定义与用法示例
Jul 05 PHP
PHP正则匹配到2个字符串之间的内容方法
Dec 24 PHP
php metaphone()函数的定义和用法
May 15 #PHP
php图片上传类 附调用方法
May 15 #PHP
php简单的上传类分享
May 15 #PHP
分享php多功能图片处理类
May 15 #PHP
非常经典的PHP文件上传类分享
May 15 #PHP
php metaphone()函数及php localeconv() 函数实例解析
May 15 #PHP
非常实用的php验证码类
May 15 #PHP
You might like
PHP var_dump遍历对象属性的函数与应用代码
2010/06/04 PHP
让codeigniter与swfupload整合的最佳解决方案
2014/06/12 PHP
PHP实现浏览器格式化显示XML的方法示例
2019/01/22 PHP
php的命名空间与自动加载实现方法
2019/08/25 PHP
用jquery ajax获取网站Alexa排名的代码
2009/12/12 Javascript
javascript中的变量是传值还是传址的?
2010/04/19 Javascript
jQuery的.live()和.die() 使用介绍
2011/09/10 Javascript
JS trim去空格的最佳实践
2011/10/30 Javascript
javascript作用域容易记错的两个地方分析
2012/06/22 Javascript
js右下角弹出提示框示例代码
2016/01/12 Javascript
jQuery 3.0 的变化及使用方法
2016/02/01 Javascript
JavaScript中递归实现的方法及其区别
2017/09/12 Javascript
AngularJS使用ng-repeat遍历二维数组元素的方法详解
2017/11/11 Javascript
JavaScript数组排序reverse()和sort()方法详解
2017/12/24 Javascript
vue中使用better-scroll实现滑动效果及注意事项
2018/11/15 Javascript
详解Vue.js 作用域、slot用法(单个slot、具名slot)
2019/10/15 Javascript
VUE中使用HTTP库Axios方法详解
2020/02/05 Javascript
js实现表格单列按字母排序
2020/08/12 Javascript
python如何拆分含有多种分隔符的字符串
2018/03/20 Python
Python cookbook(字符串与文本)针对任意多的分隔符拆分字符串操作示例
2018/04/19 Python
Python在for循环中更改list值的方法【推荐】
2018/08/17 Python
pygame游戏之旅 创建游戏窗口界面
2018/11/20 Python
Python爬虫文件下载图文教程
2018/12/23 Python
PyQt5 实现字体大小自适应分辨率的方法
2019/06/18 Python
如何基于Python实现电子邮件的发送
2019/12/16 Python
Python底层封装实现方法详解
2020/01/22 Python
使用Python实现微信拍一拍功能的思路代码
2020/07/09 Python
德国运动营养和健身网上商店:Myprotein.de
2018/07/18 全球购物
Emma Bridgewater官网:英国餐具制造商
2019/11/24 全球购物
请说出几个常用的异常类
2013/01/08 面试题
Linux如何压缩可执行文件
2014/03/27 面试题
体育教育毕业生自荐信
2013/11/21 职场文书
关工委先进个人事迹材料
2014/05/23 职场文书
上课迟到检讨书范文
2015/05/06 职场文书
中考百日冲刺决心书
2015/09/22 职场文书
九年级化学教学反思
2016/02/22 职场文书