zoukankan      html  css  js  c++  java
  • ThinkPHP 3.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 TestController;
    use ThinkController;
    
    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 ThinkVerify();
            //$verify->useZh = true;  //使用中文验证码
            $verify->length = 4; 
            $verify->entry();
        }
    
        //验证登录
        public function check(){
            $verify = new ThinkVerify();
            if($verify->check(I("yzm"))){
                //判断用户名密码
                $user = new TestModelTestModel();
                $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 = "ThinkVerify";
            //第三个参数为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 TestModelTestModel();
            $is_long = $check->checkRemember();
            if($is_long === false){
                
            }else{
                session("username",$is_long['uname']);
                session("id",$is_long['uid']);
            }
        }
    
    }

    模型 TestModel.class.php

    <?php
    namespace TestModel;
    use ThinkModel;
    
    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

  • 相关阅读:
    数组和json的相互转换
    cocoapods安装完第三方类库后不生成workspace
    CoreDataManager-OC版-兼容iOS10以前的版本
    CoreDataManager-Swift版-兼容iOS10以前的版本
    画虚线
    YYText-显示富文本
    删除项目中的CocoaPods
    CocoaPods的安装
    CocoaPods常用终端命令及Profile文件简单介绍
    根据字符串生成类---类的类型.self---根据字符串创建控制器对象
  • 原文地址:https://www.cnblogs.com/dee0912/p/4285221.html
Copyright © 2011-2022 走看看