轶哥

妄图改变世界的全栈程序员。

    HTML5用户身份认证源代码:注册、登录、会话保持的解决方案

    目录
    1. MySQL数据库管理员表 admin.sql
    2. 用户注册表单 register.html
    3. 用户注册Ajax代码 register.js
    4. PHP数据库连接文件 connect.php
    5. 用户注册后端处理PHP代码 register.php
    6. 用户登录表单 sign.html
    7. 用户登录Ajax代码 sign.js
    8. 用户登录后端处理 sign.php
    9. 用户身份认证前端代码
    10. 注销代码
    11. 用户身份认证后端代码 access.php
    12. 代码使用说明

      本文是针对PHP新手的Session教程 —— 用户注册、登录、身份认证。以下代码均为伪代码,正式项目中需要修改完善强化其安全性。

    MySQL数据库管理员表 admin.sql

    # table admin
    # ------------------------------------------------------------
    
    CREATE TABLE `admin` (
      `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
      `username` varchar(30) DEFAULT NULL,
      `password` varchar(500) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    INSERT INTO `admin` (`id`, `username`, `password`)
    VALUES
        (1,'admin','admin');
    

    用户注册表单 register.html

    <form id="user_register">
    <label for="input_Username">用户名</label>
    <input type="text" id="input_Username" name="input_Username" placeholder="用户名" required autofocus>
    <label for="input_Password">密码</label>
    <input type="password" id="input_Password" name="input_Password" placeholder="密码" required>
    <button type="button" id="button_register">注册</button>
    </form>
    

    用户注册Ajax代码 register.js

    $("#button_register").click(function () {
            $.ajax({
                cache: false,
                url:"php/register.php",
                type: "POST",
                async: false,
                data:$("#user_register").serialize(),
                dataType:"json",
                success: function(data){
                    //处理返回结果
                    switch(data.error){
                        case "false":
                            alert("注册成功!" + "注册的用户ID为:" + data.user_id);
                            break;
                        case "Insert error":
                            alert("数据写入失败,请联系管理员");
                            break;
                        case "Username exist":
                            alert("用户名已经存在");
                            break;
                        default:
                            alert("注册出错,请联系管理员");
                    }
                },
                error: function (data) {
                    alert("数据获取失败,请检查网络连接。" );
                    console.info(data);
                }
            });
    });
    

    PHP数据库连接文件 connect.php

    <?php
    /**
    
    
    数据库连接文件
    *
    
    PDO连接MySQL数据库
    
    @author      王轶<a@wyr.me>
    
    @version     0.1
    
    @copyright   BSD
    */
    try {
     $db_ip = "localhost";   //数据库IP地址
     $db_name = "";          //数据库名称
     $db_user = "";          //数据库用户名
     $db_pass = "";          //数据库密码
     $PDO = new PDO('mysql:host='.$db_ip.';dbname='.$db_name, $db_user, $db_pass, array(
     PDO::ATTR_PERSISTENT =&gt; true , // 设置数据库连接为持久连接
     PDO::ATTR_EMULATE_PREPARES =&gt; false , // 防止SQL注入
     PDO::ATTR_ORACLE_NULLS =&gt; true , // 设置当字符串为空转换为 SQL 的 NULL
     PDO::ATTR_ERRMODE , // 设置抛出错误
     PDO::ERRMODE_EXCEPTION // 设置抛出错误
     ));//PDO数据库连接代码
    } catch (PDOException $e) {
     print "Error!: " . $e->getMessage() . "<br/>";
     die();
    }
    
    
    /**
    
    
    格式化SQL数据类型
    *
    
    @param string $theValue 目标SQL数据类型
    
    @param mixed $theType 传入需要变更类型的数据
    
    @return mixed
    */
    function GetSQLValueString($theValue, $theType)
    {
     switch ($theType) {
     case "text":
         $theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL";
         break;
     case "long":
     case "int":
         $theValue = ($theValue != "") ? intval($theValue) : "NULL";
         break;
     case "double":
         $theValue = ($theValue != "") ? doubleval($theValue) : "NULL";
         break;
     case "date":
         $theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL";
         break;
     }
     return $theValue;
    }
    

    用户注册后端处理PHP代码 register.php

      其它语言相似,判断处理后返回json。

    <?php
    require_once("connect.php");//加载数据库连接文件
    //判断是否接收到了表单数据
    if(isset($_POST["input_Username"])) {
        //写入数据前检测用户名是否存在
        $username = $_POST["input_Username"];
        $Check_Username = $PDO->query("SELECT id FROM admin WHERE username=".GetSQLValueString($username, "text"));
        $Check_Username_result = $Check_Username->fetch(PDO::FETCH_ASSOC);
        if ($Check_Username_result["id"] == null) {
            //如果用户名不存在
            $password = md5(md5("aq1ja".$_POST['input_Password']."jfsah2"));//第一次执行md5的时候在前后加上安全码,再次执行md5防止md5破解
            //这个方法虽然能够加强密码强度防止暴力破解,但有弊端,仅供参考
            $insertSQL = sprintf("INSERT INTO admin SET username = %s, password = %s",
                GetSQLValueString($username, "text"),
                GetSQLValueString($password, "text"));
            $Result = $PDO->exec($insertSQL);//执行数据库写入操作
            $back_id = $PDO->lastInsertId();//获取写入的数据id
            if ($Result == "1") {//如果成功写入一条数据
                $doc = array("error" => "false", "user_id" => $back_id);//返回当前注册用户的id,可能其它业务逻辑需要
            } else {
                $doc = array("error" => "Insert error");
            }
        }else{
            $doc = array("error" => "Username exist");//返回错误提示:用户名已经存在
        }
    }else{
        $doc = array("error" => "Illegal request");//没有接收到POST过来的表单数据,有可能是非法访问
    }
    
    $PDO = null;//关闭数据库链接
    echo json_encode($doc);//返回为json字符串
    

    用户登录表单 sign.html

    <form id="user_sign">
        <label for="input_Username" class="sr-only">用户名</label>
        <input type="text" id="input_Username" name="input_Username" placeholder="用户名" required autofocus>
         <label for="input_Password" class="sr-only">密码</label>
         <input type="password" id="input_Password" name="input_Password" placeholder="密码" required>
         <div class="checkbox">
               <label>
                      <input type="checkbox" name="remember_me" value="remember-me"> 保持登录状态
               </label>
         </div>
         <button type="button" id="button_sign">登录</button>
    </form>
    

    用户登录Ajax代码 sign.js

    		//用户登录按钮按下-提交登录表单:
            $("#button_sign").click(function () {
                $.ajax({
                    cache: false,
                    url: "php/sign.php",
                    type: "POST",
                    async: false,
                    data: $("#user_sign").serialize() + "&sign=on",//sign=on是登录,sign=off是注销
                    dataType: "json",
                    success: function (data) {
                        //处理返回结果
                        switch (data.error) {
                            case "false":
                                if (window.sessionStorage && window.localStorage) {
                                    if(data.type == "time_on"){
                                        window.localStorage["user_access"] = data.user_access;
                                    }else{
                                        window.sessionStorage["user_access"] = data.user_access;
                                    }
                                    alert("登录成功!" + "返回的随机字符串是:" + data.user_access);
                                } else {
                                    alert("浏览器不支持localStorage或sessionStorage,换chrome吧");
                                }
                                break;
                            case "Username or Password error":
                                alert("用户名或密码错误");
                                break;
                            default:
                                alert("登录出错,请联系管理员");
                        }
                    },
                    error: function (data) {
                        alert("数据获取失败,请检查网络连接。");
                        console.info(data);
                    }
                });
            });
    

    用户登录后端处理 sign.php

    <?php
    require_once("connect.php");//加载数据库连接文件
    session_start(); //标志Session的开始
    //判断是否接收到了表单数据
    if(isset($_POST["sign"]) && $_POST["sign"] == "on") {
        date_default_timezone_set("PRC");
        $select = $PDO -> query("SELECT * FROM admin WHERE username = ".GetSQLValueString($_POST["input_Username"], "text"));
        $back = $select -> fetch(PDO::FETCH_ASSOC);
        if($back["username"] == $_POST["input_Username"] && $back["password"] == md5(md5("aq1ja".$_POST['input_Password']."jfsah2"))){
            $_SESSION["username"] = $back["username"];
            $_SESSION["user_id"] = $back["id"];
            $_SESSION["star_time"] = time();
            $_SESSION["user_access"] = (string)md5(rand(100000,999999)."wiq");//生成一个随机字符串
            if(isset($_POST["remember_me"]) && $_POST["remember_me"] == "remember-me"){
                //$doc = array("error" => "false" , "type" => "time_on" , "user_access" => $_SESSION["user_access"]);这里的user_access需要写入数据库
            }else{
                $doc = array("error" => "false" , "type" => "time_off", "user_access" => $_SESSION["user_access"]);
            }
        }else{
            $doc = array("error" => "Username or Password error");
        }
    }else if(isset($_POST["sign"]) && $_POST["sign"] == "off"){
        unset($_SESSION["username"]);
        unset($_SESSION["user_access"]);
        unset($_SESSION["user_id"]);
        unset($_SESSION["star_time"]);
        $doc = array("error" => "false");
    }else{
        $doc = array("error" => "Illegal request");//没有接收到POST过来的表单数据,有可能是非法访问
    }
    
    $PDO = null;//关闭数据库链接
    echo json_encode($doc);//返回为json字符串
    

    用户身份认证前端代码

    <div id="show_on" style="display: none">
        <p id="show_text"></p>
        <a href="sign.html?sign=off">注销</a>
    </div>
    
    		//判断在线状态:
            if (window.sessionStorage && window.localStorage) {
                function sign(user_access,type){
                    $.ajax({
                        cache: false,
                        url: "php/access.php",
                        type: "POST",
                        async: false,
                        data: {"user_access":user_access},
                        dataType: "json",
                        success: function (data) {
                            //处理返回结果
                            switch (data.error) {
                                case "false":
                                    $("#show_on").show();
                                    $("#user_sign").hide();
                                    $("#show_text").text("身份认证成功!当前用户:" + data.username + " id: " + data["user_id"]);
                                    break;
                                case "No_time":
                                    if(type == "session"){
                                        window.sessionStorage.removeItem("user_access");
                                    }else{
                                        window.localStorage.removeItem("user_access");
                                    }
                                    alert("身份认证过期,请重新登录");
                                    break;
                                default:
                                    alert("数据出错,请联系管理员");
                            }
                        },
                        error: function (data) {
                            alert("数据获取失败,请检查网络连接。");
                            console.info(data);
                        }
                    });
                }
                var session = window.sessionStorage;
                if(session["user_access"]){
                    sign(session["user_access"],"session");
                }else if(window.localStorage["user_access"]){
                    sign(window.localStorage["user_access"],"local");
                }
            } else {
                alert("浏览器不支持localStorage或sessionStorage,换chrome吧");
            }
    

    注销代码

    $(function () {
            //获取URL中的参数 [分析GET过来的数据]
            function get(name){
                var geturl = window.location.search.substr(1).split("&");
                for(var n=0;n<geturl.length;n++){
                    if(decodeURIComponent(name)==geturl[n].split("=")[0]){
                        return decodeURIComponent(geturl[n].split("=")[1]);
                    }
                }
            }
    
        //注销:
        if(get("sign") == "off"){
            $.ajax({
                cache: false,
                url: "php/sign.php",
                type: "POST",
                async: false,
                data: $("#user_sign").serialize() + "&amp;sign=off",//sign=on是登录,sign=off是注销
                dataType: "json",
                success: function (data) {
                    //处理返回结果
                    switch (data.error) {
                        case "false":
                            alert("注销成功!");
                            break;
                        default:
                            alert("注销出错,请联系管理员");
                    }
                },
                error: function (data) {
                    alert("数据获取失败,请检查网络连接。");
                    console.info(data);
                }
            });
        }
    })
    

    用户身份认证后端代码 access.php

    <?php
    session_start(); //标志Session的开始
    error_reporting(0);//屏蔽报错
    date_default_timezone_set("PRC");
    if(isset($_POST["user_access"]) && $_POST["user_access"] == $_SESSION["user_access"]){
        if(time() - $_SESSION["star_time"] < 21600){
            $doc = array("error" => "false" , "username" => $_SESSION["username"], "user_id" => $_SESSION["user_id"]);
            //在这里编写认证后的业务逻辑
        }else{
            $doc = array("error" => "No_time");
        }
    } else {
        $doc = array("error" => "No_time");
    }
    echo json_encode($doc);//返回为json字符串
    

    代码使用说明

      以上代码仅为简单实例,这只是一个解决方案。安全性上还需要进一步完善。需要特别注意的是,上面的代码中的身份认证在用户关闭浏览器后随即失效,没有实现登录状态的长期保持,可以使用localStorage来保存本地的随机码(需要处理数据库配合)。在用户身份认证的时候比对数据库里面的信息判断localStorage中的随机码是否失效。

      上一篇 (C#扫描在线IP源代码-多媒体教室、公司内网管理IP搜索)
    下一篇 (发展中的云计算)