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实现的获取URL信息的类
Jan 02 PHP
PHP+ACCESS 文章管理程序代码
Jun 21 PHP
Window 7/XP 安装Apache 2.4与PHP 5.4 的过程详解
Jun 02 PHP
php中mail函数发送邮件失败的解决方法
Dec 24 PHP
php实现通用的信用卡验证类
Mar 24 PHP
CodeIgniter配置之SESSION用法实例分析
Jan 19 PHP
Yii实现简单分页的方法
Apr 29 PHP
PHP策略模式定义与用法示例
Jul 27 PHP
使用PHPStorm+XDebug搭建单步调试环境
Nov 19 PHP
php封装实现钉钉机器人报警接口的示例代码
Aug 08 PHP
phpstudy隐藏index.php的方法
Sep 21 PHP
PHP safe_mode开启对于PHP系统函数有什么影响
Nov 10 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安全编程之加密功能
2006/10/09 PHP
利用浏览器的Javascript控制台调试PHP程序
2014/01/08 PHP
thinkphp文件引用与分支结构用法实例
2014/11/26 PHP
经典PHP加密解密函数Authcode()修复版代码
2015/04/05 PHP
PHP析构函数destruct与垃圾回收机制的讲解
2019/03/22 PHP
Thinkphp框架使用list_to_tree 实现无限级分类列出所有节点示例
2020/04/04 PHP
jquery-easyui关闭tab自动切换到前一个tab
2010/07/29 Javascript
JavaScript中访问节点对象的方法有哪些如何使用
2013/09/24 Javascript
window.location 对象所包含的属性
2014/10/10 Javascript
浅析jQuery EasyUI中的tree使用指南
2014/12/18 Javascript
JavaScript设置body高度为浏览器高度的方法
2015/02/09 Javascript
DOM操作一些常用的属性汇总
2015/03/13 Javascript
JavaScript中的anchor()方法使用详解
2015/06/08 Javascript
mui back 返回刷新页面的实例
2017/12/06 Javascript
微信小程序ajax实现请求服务器数据及模版遍历数据功能示例
2017/12/15 Javascript
简单的Vue异步组件实例Demo
2017/12/27 Javascript
jQuery实现基本动画效果的方法详解
2018/09/06 jQuery
解决axios会发送两次请求,有个OPTIONS请求的问题
2018/10/25 Javascript
layer的prompt弹出框,点击回车,触发确定事件的方法
2019/09/06 Javascript
小程序实现图片预览裁剪插件
2019/11/22 Javascript
[00:34]TI7不朽珍藏III——地穴编织者不朽展示
2017/07/15 DOTA
python正则表达式re模块详细介绍
2014/05/29 Python
Python使用min、max函数查找二维数据矩阵中最小、最大值的方法
2018/05/15 Python
详解配置Django的Celery异步之路踩坑
2018/11/25 Python
Python 剪绳子的多种思路实现(动态规划和贪心)
2020/02/24 Python
加拿大健康、婴儿和美容产品在线购物:Well.ca
2016/11/30 全球购物
台湾旅游网站:雄狮旅游网
2017/08/16 全球购物
印度服装购物网站:Limeroad
2018/09/26 全球购物
澳大利亚购买健身器材网站:Gym Direct
2019/12/19 全球购物
单位工程竣工验收方案
2014/03/16 职场文书
暑假家长评语大全
2014/04/17 职场文书
大学生见习报告总结
2014/11/04 职场文书
物资采购管理制度
2015/08/06 职场文书
小学秋季运动会加油口号及加油稿
2019/08/19 职场文书
导游词之桂林山水
2019/09/20 职场文书
JavaScript高级程序设计之基本引用类型
2021/11/17 Javascript