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 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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM