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 高手之路(二)
Oct 09 PHP
PHP 用数组降低程序的时间复杂度
Dec 04 PHP
php设计模式 Mediator (中介者模式)
Jun 26 PHP
浅析Mysql 数据回滚错误的解决方法
Aug 05 PHP
php 获取页面中指定内容的实现类
Jan 23 PHP
php快递单号查询接口使用示例
May 05 PHP
PHP实现检测客户端是否使用代理服务器及其匿名级别
Jan 07 PHP
php中执行系统命令的方法
Mar 21 PHP
给WordPress中的留言加上楼层号的PHP代码实例
Dec 14 PHP
PHP Header失效的原因分析及解决方法
Nov 16 PHP
php实现的简单中文验证码功能示例
Jan 03 PHP
PHP字典树(Trie树)定义与实现方法示例
Oct 09 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
中国广播史趣谈 — 几个历史第一次
2021/03/01 无线电
PHP的开合式多级菜单程序
2006/10/09 PHP
php array_unique之后json_encode需要注意
2011/01/02 PHP
php 下载保存文件保存到本地的两种实现方法
2013/08/12 PHP
jQuery的12招常用技巧分享
2011/08/08 Javascript
JS实现淘宝幻灯片效果的实现方法
2013/03/22 Javascript
浅析jQuery对select操作小结(遍历option,操作option)
2013/07/04 Javascript
jquery ajax修改全局变量示例代码
2013/11/08 Javascript
javascript中动态加载js文件多种解决办法总结
2013/11/15 Javascript
JS 屏蔽键盘不可用与鼠标右键不可用的方法
2013/11/18 Javascript
解决jquery中美元符号命名冲突问题
2014/01/08 Javascript
node.js使用require()函数加载模块
2014/11/26 Javascript
jquery实现移动端点击图片查看大图特效
2020/09/11 Javascript
WebGL利用FBO完成立方体贴图效果完整实例(附demo源码下载)
2016/01/26 Javascript
jQuery实现遍历XML节点和属性的方法示例
2018/04/29 jQuery
webpack实践之DLLPlugin 和 DLLReferencePlugin的使用教程
2019/06/10 Javascript
vue实现codemirror代码编辑器中的SQL代码格式化功能
2019/08/27 Javascript
axios解决高并发的方法:axios.all()与axios.spread()的操作
2020/11/09 Javascript
[39:02]DOTA2亚洲邀请赛 3.31 小组赛 B组 Mineski vs VGJ.T
2018/04/01 DOTA
浅谈Python单向链表的实现
2015/12/24 Python
windows下python安装pip图文教程
2018/05/25 Python
Python走楼梯问题解决方法示例
2018/07/25 Python
python3 通过 pybind11 使用Eigen加速代码的步骤详解
2020/12/07 Python
浅析pandas随机排列与随机抽样
2021/01/22 Python
通过css3动画和opacity透明度实现呼吸灯效果
2019/08/09 HTML / CSS
美国著名的团购网站:Woot
2016/08/02 全球购物
澳大利亚最好的在线时尚精品店:Princess Polly
2018/01/03 全球购物
芭比波朗加拿大官方网站:Bobbi Brown Cosmetics CA
2020/11/05 全球购物
企业后勤岗位职责
2014/02/28 职场文书
理财学专业自荐书
2014/06/28 职场文书
护士求职自荐信范文
2015/03/04 职场文书
河童之夏观后感
2015/06/11 职场文书
初中英语教学反思范文
2016/02/15 职场文书
承诺书的内容有哪些,怎么写?
2019/06/21 职场文书
Python NumPy灰度图像的压缩原理讲解
2021/08/04 Python
MySQL空间数据存储及函数
2021/09/25 MySQL