登陆身份识别机制(Session工作机制,PHP版)【含登陆程序脚本】
写在前面
当登录时究竟发生了什么?如何去追踪关键信息,关键信息又在哪里?看了很多不管是http基本认证
还是session
的机制,体会不够深,还是不如自己边写边理解和记忆来的深刻。
参考资料:《PHP、MySQL与JavaScript学习手册》 第五版 --中国电力出版社
希望能对你理解登陆身份识别上有所帮助。
基础知识
这里仅简单说一说。
cookie
在首部中交换,在网页的html
内容之前发送,html
一旦发送,就无法再发送cookie
了。
例如:
1.浏览器发起请求,请求头会指定请求文件路径和服务器
2.服务器收到这些首部后,也会返回首部,这里返回的首部之一,就有Set-cookie: name=value
3.收到cookie后,后续每次对签发服务器的请求都会带上cookie,就是Cookie: name=value
4.服务器收到带cookie的请求,不再发送cookie,返回被请求的页面。
资料引用:
由于 Session 是以文本文件形式存储在服务器端的,所以不怕客户端修改 Session 内容。实际上在服务器端的 Session 文件,PHP 自动修改 Session 文件的权限,只保留了系统读和写权限,而且不能通过 ftp 修改,所以安全得多。
对于 Cookie 来说,假设我们要验证用户是否登陆,就必须在 Cookie 中保存用户名和密码(可能是 md5 加密后字符串),并在每次请求页面的时候进行验证。如果用户名和密码存储在数据库,每次都要执行一次数据库查询,给数据库造成多余的负担。因为我们并不能 只做一次验证。为什么呢?因为客户端 Cookie 中的信息是有可能被修改的。假如你存储 $admin 变量来表示用户是否登陆,$admin 为 true 的时候表示登陆,为 false 的时候表示未登录,在第一次通过验证后将 $admin 等于 true 存储在 Cookie,下次就不用验证了,这样对么?错了,假如有人伪造一个值为 true 的 $admin 变量那不是就立即取的了管理权限么?非常的不安全。
而 Session 就不同了,Session 是存储在服务器端的,远程用户没办法修改 Session 文件的内容,因此我们可以单纯存储一个 $admin 变量来判断是否登陆,首次验证通过后设置 $admin 值为 true,以后判断该值是否为 true,假如不是,转入登陆界面,这样就可以减少很多数据库操作了。而且可以减少每次为了验证 Cookie 而传递密码的不安全性了(Session 验证只需要传递一次,假如你没有使用 SSL 安全协议的话)。即使密码进行了 md5 加密,也是很容易被截获的。
资料参考链接:https://blog.csdn.net/a5605005/article/details/101153131
程序一
这里不再涉及到http基本身份认证
,基本身份认证具有一定的漏洞,同时运用范围不算很广。这里我们直接使用session
版的登陆方法。
首先来test一下,查看一下session的结构,脚本:
<?php
session_start();
$_SESSION['admin']=null;
在网页中执行一下(网页上是一片白),抓包看看:
这里进行了session_id
的设置,当我们请求localhost
的其他相关资源时,就会带上刚才设置过的session_id
,就像这样:
session
就开始工作了,在服务器上看看session
的样子:
文件类似如下:
如果你也想在本地服务器查看,一般会存放在tmp
目录下,可以找找。
查看后保存结果如下:
admin|N;
保存规则:
变量名|类型:长度:值;
并用分号隔开每个变量。有些是可以省略的,比如长度和类型。
程序二
来一个完整的登陆程序,由于我们这里只讨论session
。这里的html,数据库等等操作就略过了,找了其他同学的资源:
index.php
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>php登录测试</title>
</head>
<body>
<form action="register.php" method="POST" >
<label>用户名:</label>
<input type = "text" name = "username"/> <br/>
<label>密码:</label>
<input type = "password" name="password"/> <br/>
<input type = "submit" value = "提交"/>
</form>
</body>
</html>
register.php
<?php
header("Content-type: text/html; charset=utf-8");
session_start(); //session开始
//$_POST用户名和密码
$username = $_POST['username'];
$password = $_POST['password'];
//连接mysql
$con = mysqli_connect('localhost','root','', '');
//验证mysql连接是否成功
if(mysqli_errno($con)){
echo "连接mysql失败:".mysqli_error($con);
exit;
}
//sql查询语句
$sql = "select id from security.users where username='$username' and password='$password'";
//执行
$result = mysqli_query($con,$sql);
$num = mysqli_num_rows($result); // 函数返回结果集中行的数量
if($num){
echo "<script>alert('登录成功');</script>";
} else{
die( "<script>alert('登录失败,不存在此用户');</script>");
}
$row = mysqli_fetch_assoc($result);
$_SESSION['userid'] = $row['id']; // session值设置
mysqli_close($con);
echo "<script>window.location.href = 'show.php'</script>";
?>
show.php
<?php
header("Content-type: text/html; charset=utf-8");
session_start();
$userid = $_SESSION['userid']; // 读取前面设置的session值
//连接mysql
$con = mysqli_connect('localhost','root','', '');
//验证mysql连接是否成功
if(mysqli_errno($con)){
echo "连接mysql失败:".mysqli_error($con);
exit;
}
//sql查询语句
$sql = "select username from security.users where id='{$userid}'";
//执行
$result = mysqli_query($con,$sql);
$row = mysqli_fetch_assoc($result);
$name = $row['username'];
$talk= 'i am talk';
mysqli_close($con);
?>
<!DOCTYPE html>
<html>
<head>
<title>用户信息</title>
</head>
<body>
<p>
用户名:
<?php
echo $name;
?>
</p>
<p>
个人简介:
<?php
echo $talk;
?>
</p>
</body>
</html>
数据库构建
注:如果你要在自己的环境上复现,注意修改数据库密码和连接的库,还有相关字段的修改。
普通运行展示
分别输入 123
123
返回输入 admin
admin123
(数据库里设置的账号密码)
基本功能完成
抓包查看
上面例子要重点关注关于session
的注释,如果你仔细看,session
在这里起到了一个公共量传递的作用,让键值对可以跨网页(文件)使用。
这里我们已经设置过一个session
发出请求时就会带上PHPSESSID
,由唯一的session_id
来表示独属于当前用户的session
。这样就能够靠session
传递个性化信息了。
这里我们的session_id是 k34lhop0qudc0nudm38oblp933
我们从服务器端直接读取更加直接的看看
在tmp
下找到;
打开:
就是传递了我们设置的userid
以上就是session
在变量传递中的作用。
程序三
当然session
另一个作用就是权限维护,在登陆完成后的session
生效期间,可以不必再次登录,维护一定时间的权限。
由于写的时候隔了一天,优化了一点点。
在register.php
当中,当查询到有效值之后,改成这样:
$result = mysqli_query($con,$sql);
$num = mysqli_num_rows($result); // 函数返回结果集中行的数量
if($num)
{
echo "<script>alert('Welcome');</script>";
session_start();
$row = mysqli_fetch_assoc($result);
$_SESSION['admin']=true;
$_SESSION['userid'] = $row['id']; // session
}
else
{
die( "<script>alert('Login false! Please check');window.location.href = 'index.php'</script>");
}
这里将session
操作放入了if中,同时对session
多了一步操作:
$_SESSION['admin']=true;
然后在index.php
的前面加上这个(因为要用php,又改成php后缀了)
<?php
$admin=false;
session_start();
if(isset($_SESSION['admin'])===true)
{
echo "<script>window.location.href='show.php'</script>";
}
?>
这其实就是一个简单的验证程序,如果你的session符合要求,就可以直接进入后续界面,如果不符合要求,就会进入常规登录界面。
当然,这样可以放在任何你想要验证是否登录的界面上。
测试结果当然就是,当你登录成功后的一段时间内,可以无需登录,直接进入show.php
权限维持就成功了
延伸
如果我们还有一个注销下线的功能,那当然就需要将当前的session
摧毁。后续优化一下再写新的。