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 相关文章推荐
使用adodb lite解决问题
Dec 31 PHP
六酷社区论坛HOME页清新格调免费版 下载
Mar 07 PHP
php学习 函数 课件
Jun 15 PHP
php 数据库字段复用的基本原理与示例
Jul 22 PHP
php smarty模板引擎的6个小技巧
Apr 24 PHP
php实现将字符串按照指定距离进行分割的方法
Mar 14 PHP
php上传图片类及用法示例
May 11 PHP
php输出含有“#”字符串的方法
Jan 18 PHP
PHP魔术方法之__call与__callStatic使用方法
Jul 23 PHP
浅谈laravel 5.6 安装 windows上使用composer的安装过程
Oct 18 PHP
在laravel中实现ORM模型使用第二个数据库设置
Oct 24 PHP
php框架知识点的整理和补充
Mar 01 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
四个常见html网页乱码问题及解决办法
2015/09/08 PHP
PHP url的pathinfo模式加载不同控制器的简单实现
2016/08/12 PHP
php利用嵌套数组拼接与解析json的方法
2017/02/07 PHP
PHP中通过getopt解析GNU C风格命令行选项
2019/11/18 PHP
php设计模式之适配器模式实例分析【星际争霸游戏案例】
2020/04/07 PHP
JavaScript Event事件学习第一章 Event介绍
2010/02/07 Javascript
jQuery.validate 常用方法及需要注意的问题
2013/03/20 Javascript
JavaScript运行时库属性一览表
2014/03/14 Javascript
javascript实现炫酷的拖动分页
2015/05/11 Javascript
跟我学习javascript的prototype,getPrototypeOf和__proto__
2015/11/17 Javascript
jquery if条件语句的写法
2016/05/19 Javascript
前端框架Vue.js中Directive知识详解
2016/09/12 Javascript
Bootstrap字体图标无法正常显示的解决方法
2016/10/08 Javascript
Angular自定义组件实现数据双向数据绑定的实例
2017/12/11 Javascript
bootstrap-table实现表头固定以及列固定的方法示例
2019/03/07 Javascript
Vue实现商品详情页的评价列表功能
2019/09/04 Javascript
[41:56]Spirit vs Liquid Supermajor小组赛A组 BO3 第一场 6.2
2018/06/03 DOTA
深入理解python try异常处理机制
2016/06/01 Python
机器学习的框架偏向于Python的13个原因
2017/12/07 Python
Python操作mongodb数据库进行模糊查询操作示例
2018/06/09 Python
python高效过滤出文件夹下指定文件名结尾的文件实例
2018/10/21 Python
python3 自动打印出最新版本执行的mysql2redis实例
2020/04/09 Python
Python3 requests模块如何模仿浏览器及代理
2020/06/15 Python
python 实现表情识别
2020/11/21 Python
AmazeUI 等分网格的实现示例
2020/08/25 HTML / CSS
在Java开发中如何选择使用哪种集合类
2016/08/09 面试题
医药大学生求职简历的自我评价
2013/10/17 职场文书
交通事故检查书范文
2014/01/30 职场文书
最新结婚典礼主持词
2014/03/14 职场文书
作文评语集锦大全
2014/04/23 职场文书
防邪知识进家庭活动方案
2014/08/26 职场文书
党员十八大心得体会
2014/09/12 职场文书
看上去很美观后感
2015/06/10 职场文书
幼儿园庆元旦主持词
2015/07/06 职场文书
Windows中Redis安装配置流程并实现远程访问功能
2021/06/07 Redis
关于Python使用turtle库画任意图的问题
2022/04/01 Python