惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

TaoSecurity Blog
TaoSecurity Blog
T
Troy Hunt's Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Vercel News
Vercel News
T
Threatpost
G
Google Developers Blog
T
Threat Research - Cisco Blogs
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
The Exploit Database - CXSecurity.com
H
Heimdal Security Blog
Google DeepMind News
Google DeepMind News
Cyberwarzone
Cyberwarzone
T
The Blog of Author Tim Ferriss
Know Your Adversary
Know Your Adversary
Hacker News: Ask HN
Hacker News: Ask HN
www.infosecurity-magazine.com
www.infosecurity-magazine.com
S
Schneier on Security
B
Blog
V2EX - 技术
V2EX - 技术
NISL@THU
NISL@THU
C
CERT Recently Published Vulnerability Notes
W
WeLiveSecurity
C
Cybersecurity and Infrastructure Security Agency CISA
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Y
Y Combinator Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Spread Privacy
Spread Privacy
The Last Watchdog
The Last Watchdog
V
Vulnerabilities – Threatpost
N
Netflix TechBlog - Medium
Schneier on Security
Schneier on Security
F
Fortinet All Blogs
N
News | PayPal Newsroom
Attack and Defense Labs
Attack and Defense Labs
Blog — PlanetScale
Blog — PlanetScale
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Microsoft Security Blog
Microsoft Security Blog
S
Security @ Cisco Blogs
人人都是产品经理
人人都是产品经理
爱范儿
爱范儿
P
Privacy & Cybersecurity Law Blog
P
Proofpoint News Feed
Project Zero
Project Zero
I
Intezer
罗磊的独立博客
H
Hackread – Cybersecurity News, Data Breaches, AI and More
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - Franky
SecWiki News
SecWiki News
Martin Fowler
Martin Fowler

轶哥博客

blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog
blog
2015-11-20 · via 轶哥博客

  本文是针对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中的随机码是否失效。