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 相关文章推荐
基于mysql的论坛(5)
Oct 09 PHP
php获取本地图片文件并生成xml文件输出具体思路
Apr 27 PHP
基于AppServ,XAMPP,WAMP配置php.ini去掉警告信息(NOTICE)的方法详解
May 07 PHP
PHP中使用CURL模拟登录并获取数据实例
Jul 01 PHP
PHP中的日期加减方法示例
Aug 21 PHP
支付宝接口开发集成支付环境小结
Mar 17 PHP
PHP类的声明与实例化及构造方法与析构方法详解
Jan 26 PHP
WordPress中设置Post Type自定义文章类型的实例教程
May 10 PHP
yii2实现分页,带搜索的分页功能示例
Jan 07 PHP
ThinkPHP实现静态缓存和动态缓存示例代码
May 02 PHP
PHP实现会员账号单唯一登录的方法分析
Mar 07 PHP
mac pecl 安装php7.1扩展教程
Oct 17 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利用反射实现插件机制的方法
2015/03/14 PHP
php实现表单多按钮提交action的处理方法
2015/10/24 PHP
PHP读取CSV大文件导入数据库的实例
2017/07/24 PHP
YII框架行为behaviors用法示例
2019/04/26 PHP
PHP文件类型检查及fileinfo模块安装使用详解
2019/05/09 PHP
PHP Redis扩展无法加载的问题解决方法
2019/08/22 PHP
PHP var关键字相关原理及使用实例解析
2020/07/11 PHP
ExtJs中简单的登录界面制作方法
2010/08/19 Javascript
防止xss和sql注入:JS特殊字符过滤正则
2013/04/18 Javascript
Javascript高级技巧分享
2014/02/25 Javascript
JavaScript中的方法重载实例
2015/03/16 Javascript
node模块机制与异步处理详解
2016/03/13 Javascript
使用JS中的exec()方法构造正则表达式验证
2016/08/01 Javascript
关于JavaScript中事件绑定的方法总结
2016/10/26 Javascript
详解组件库的webpack构建速度优化
2018/06/18 Javascript
swiper Scrollbar滚动条组件详解
2019/09/08 Javascript
python妙用之编码的转换详解
2017/04/21 Python
python中解析json格式文件的方法示例
2017/05/03 Python
python学习教程之Numpy和Pandas的使用
2017/09/11 Python
Python实现PS滤镜特效Marble Filter玻璃条纹扭曲效果示例
2018/01/29 Python
Python扩展内置类型详解
2018/03/26 Python
用python实现k近邻算法的示例代码
2018/09/06 Python
pandas 将索引值相加的方法
2018/11/15 Python
Python sklearn KFold 生成交叉验证数据集的方法
2018/12/11 Python
python正则表达式匹配[]中间为任意字符的实例
2018/12/25 Python
python开发准备工作之配置虚拟环境(非常重要)
2019/02/11 Python
Python如何使用k-means方法将列表中相似的句子归类
2019/08/08 Python
python 三元运算符使用解析
2019/09/16 Python
python安装及变量名介绍详解
2020/12/12 Python
Martinelli官方商店:西班牙皮鞋和高跟鞋品牌
2019/07/30 全球购物
能否解释一下XSS cookie盗窃是什么意思
2012/06/02 面试题
音乐学个人的自荐书范文
2013/11/26 职场文书
毕业生自荐信格式
2014/03/07 职场文书
个人德育工作总结
2015/03/05 职场文书
傅雷家书读书笔记
2015/06/29 职场文书
设置IIS Express并发数
2022/07/07 Servers