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

首先,持久登陆使用 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>Document</title>
</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持久登录、记住我功能实现:http://blog.csdn.net/clh604/article/details/20282945

php生成包含数字,大小写英文字母的随机字符串:http://www.oschina.net/code/snippet_616695_22223

ThinkPHP 3.2.2 实现持久登录 ( 记住我 )的更多相关文章

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

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

  2. android 入门 005(登录记住)

    android 入门 005(登录记住) <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android ...

  3. Jquery 实现 “下次自动登录” 记住用户名密码功能

    转载自:http://blog.csdn.net/aspnet_lyc/article/details/12030039?utm_source=tuicool&utm_medium=refer ...

  4. SharedPreferences实现自动登录记住用户名密码

    最近Android项目需要一个自动登录功能,完成之后,特总结一下,此功能依靠SharedPreferences进行实现.   SharedPreferences简介 SharedPreferences ...

  5. Android SharedPreferences登录记住密码

    SharedPreferences是Android中存储简单数据的一个工具类.可以想象它是一个小小的Cookie,它通过用键值对的方式把简单 数据类型(boolean.int.float.long和S ...

  6. Cookie实现登录记住密码

    Cookie实现记住登录密码,用户可以自由选择是否记住密码,或者用户之前选择记住了,但是某一次又不想记住了,需要将之前对应的Cookie删除掉 Cookie相当于map 也是键值对的形式,但是并不相同 ...

  7. QT 登录记住密码方法之一:Qt QSettings读写配置文件

    不过本文写的是明文保存,最好还是加密一下,以防文件被非法读取 /**登录初始化的时候处理这部分操作*/ Settings cfg("user.ini",QSettings::Ini ...

  8. shiro 实现 网站登录记住我功能 学习记录(四)

    在很多网站都有在登录的时候,比如说记住我 几天之内  只要再此打开这个网站,都不需要再登录的情况: 1.前台JSP增加 单选框:记住我 如 2.在处理登录的 Controller 代码中增加接收这个参 ...

  9. 【MVC5】使用域用户登录+记住我

    1.配置Web.config文件 添加域链接字符串 <connectionStrings> <add name="ADConnectionString" conn ...

随机推荐

  1. stm32学习笔记----双串口同时打开时的printf()问题

    stm32学习笔记----双串口同时打开时的printf()问题 最近因为要使用串口2外接PN532芯片实现通信,另一方面,要使用串口1来将一些提示信息输出到上位机,于是重定义了printf(),使其 ...

  2. soft lockup和hard lockup介绍

    转自:http://www.cnblogs.com/openix/p/4034530.html 转自:http://blog.csdn.net/panzhenjie/article/details/1 ...

  3. [译]SQL Server 之 查询计划缓存和重编译

    查询优化是一个复杂而且耗时的操作,所以SQL Server需要重用现有的查询计划.查询计划的缓存和重用在多数情况下是有益的的,但是在某些特殊的情况下,重编译一个查询计划可能能够改善性能. SELECT ...

  4. js 完全分离 window.onload=

    js 完全分离  window.onload= <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" ...

  5. C# 从入门到精通

    int i=null; int? i=null; 我们用一个问号 来指定这个值类型是可空的 属性是只读的

  6. IOS杂谈

    1 IOS名称是iPhone Operating System 的缩写,原本这个系统名为iPhone OS,意思是iPhone 操作系统. 2 IOS的开发环境是Xcode.Xcode就成为了iPho ...

  7. Hark的数据结构与算法练习之计数排序

    算法说明 计数排序属于线性排序,它的时间复杂度远远大于常用的比较排序.(计数是O(n),而比较排序不会超过O(nlog2nJ)). 其实计数排序大部分很好理解的,唯一理解起来很蛋疼的是为了保证算法稳定 ...

  8. Linux常用命令_(文件权限)

    Linux权限管理: 二.权限管理1.3种基本权限在Linux中,将使用系统资源的人员分为4类:超级用户.文件或目录的属主.属主的同组人和其他人员.超级用户拥有对Linux系统一切操作权限,对 于其他 ...

  9. js:数据结构笔记13--检索算法

    顺序查找:也称线性查找,暴力查找的一种 基本格式: var nums = []; for(var i = 0; i < 10; ++i) { nums[i] = Math.floor(Math. ...

  10. DFS ZOJ 1002/HDOJ 1045 Fire Net

    题目传送门 /* 题意:在一个矩阵里放炮台,满足行列最多只有一个炮台,除非有墙(X)相隔,问最多能放多少个炮台 搜索(DFS):数据小,4 * 4可以用DFS,从(0,0)开始出发,往(n-1,n-1 ...