🐘身份鉴权(PHP)
免责声明:本文章仅用于交流学习,因文章内容而产生的任何违法&未授权行为,与文章作者无关!!!
附:完整笔记目录~
ps:本人小白,笔记均在个人理解基础上整理,若有错误欢迎指正!
1.2 🐘身份鉴权(PHP)
-
引子:上一章主要对PHP中全局变量做了介绍,其中
$_COOKIE
、$_SESSION
常常在身份鉴权中被使用。而本章则是由代码具体聊聊在PHP Web中开发者所常使用的身份鉴权方式。
这里再简单介绍一下身份鉴权,确认用户&系统在访问某受限资源时,身份是否合法。若想具体了解各鉴权方式的工作流程&优缺点,可参考:https://www.cnblogs.com/sjjjjer/p/18603336 -
Http基本鉴权
由用户名&密码确认用户身份,是最基础但也最麻烦的鉴权方式,即用户每一次访问任意的受限资源前都需要输入用户名密码。接下来我们写一个本地demo。-
首先写一个登录框。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>登录</title> <link rel="stylesheet" href="styles.css"> </head> <body> <div class="login-container"> <h2>后台登录</h2> <form action="BasiccheckDemo1.php" method="POST"> <div class="form-group"> <label for="username">用户名</label> <input type="text" id="username" name="username" required> </div> <div class="form-group"> <label for="password">密码</label> <input type="password" id="password" name="password" required> </div> <button type="submit" class="login-btn">登录</button> </form> </div> <?php if (isset($_GET['error'])){ echo "<script>alert('用户名或密码错误!');</script>"; echo "<script> // 使 URL 仅保留原路径而不携带任何参数 history.replaceState(null, null, window.location.pathname); </script>"; } ?> </body> </html>
-
其次再写一个登录框样式,使其美观一些,styles.css:
body { font-family: Arial, sans-serif; background: linear-gradient(135deg, #ff9a9e, #fad0c4); display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; } .login-container { background-color: #ffffff; padding: 20px 30px; border-radius: 8px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); width: 100%; max-width: 400px; } .login-container h2 { margin: 0 0 20px; font-size: 24px; text-align: center; color: #333; } .form-group { margin-bottom: 15px; } .form-group label { display: block; margin-bottom: 5px; color: #555; } .form-group input { width: 100%; padding: 10px; border: 1px solid #ccc; border-radius: 4px; font-size: 14px; } .form-group input:focus { outline: none; border-color: #2575fc; box-shadow: 0 0 4px rgba(37, 117, 252, 0.5); } .login-btn { display: block; width: 100%; padding: 10px; background-color: #2575fc; border: none; border-radius: 4px; font-size: 16px; color: #fff; cursor: pointer; transition: background-color 0.3s ease; } .login-btn:hover { background-color: #1e63d9; } .login-container p { margin-top: 15px; text-align: center; font-size: 14px; } .login-container p a { color: #2575fc; text-decoration: none; } .login-container p a:hover { text-decoration: underline; }
-
效果展示
貌似也没那么美观哈哈~ -
接下来再创建一个mysql数据库,库中存放着管理员的用户名&密码,用于后面的身份认证。
-- 创建&使用数据库 CREATE DATABASE IF NOT EXISTS authentication; USE authentication; -- 创建用户表 CREATE TABLE IF NOT EXISTS users ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(255) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- 在表中插入数据 INSERT INTO users (username, password) VALUES ('admin', 'sjjjer');
-
写一个数据库配置文件,用于php与数据库间通信。
<?php // 数据库配置 $host = 'localhost'; // 数据库主机名 $dbname = 'authentication'; // 数据库名 $username = 'root'; // 数据库用户名 $password = '123456'; // 数据库密码 define('DB_HOST', $host); define('DB_NAME', $dbname); define('DB_USERNAME', $username); define('DB_PASSWORD', $password);
-
再写身份认证逻辑。
<?php // 引入数据库配置文件 include 'db_config.php'; // 连接数据库 $conn = mysqli_connect(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_NAME); // 获取表单所提交的 username password $username = $_POST["username"]; $password = $_POST["password"]; // 判断获取到的 username password 是否在数据库中有所记录 $sql = "SELECT * FROM users WHERE username = '$username' and password = '$password'"; // 将查询结果存储至 $result 中 $result = mysqli_query($conn, $sql); // 获取 $result 中的行数并判断,也就是 $sql 所获取结果的行数 if (mysqli_num_rows($result) > 0) { header('Location: admin.php'); exit(); }else{ header('Location: login.php?error=1'); exit(); } // 关闭数据库连接 mysqli_close($conn);
-
最后写一个后台页面。
<?php echo "欢迎来到后台!";
-
测试一下这段简单的demo
由上述案例可知,只有当post所提交的用户名密码正确时,才会跳转至后台页面。可后台页面往往有很多,为了防止其他用户也能访问后台,难道要在每一个后台页面前都要加上判断用户名&密码是否正确的逻辑吗?于开发者&用户而言,很麻烦也没有必要,因此出现了Session-Cookie鉴权。
-
-
Cookie鉴权
当用户输入正确的用户名&密码时,服务端(一般情况下)会由所输入的用户名&密码生成Cookie,并将生成的Cookie返回给浏览器,浏览器收到Cookie并保存,当用户再次访问受限页面时会携带浏览器所保存的Cookie,而被访问页面仅需判断Cookie是否合法来实现身份鉴权,无需用户再次输入用户名&密码。-
基于Cookie的身份认证逻辑:
<?php // 引入数据库配置文件 include 'db_config.php'; // 连接数据库 $conn = mysqli_connect(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_NAME); // 获取表单所提交的 username password $username = $_POST["username"]; $password = $_POST["password"]; // 判断获取到的 username password 是否在数据库中有所记录 $sql = "SELECT * FROM users WHERE username = '$username' and password = '$password'"; // 将查询结果存储至 $result 中 $result = mysqli_query($conn, $sql); // 获取 $result 中的行数并判断,也就是 $sql 所获取结果的行数 if (mysqli_num_rows($result) > 0) { setcookie("username", $username, time() + (86400), "/"); setcookie("password", $password, time() + (86400), "/"); header('Location: admin.php'); exit(); }else{ header('Location: login.php?error=1'); exit(); } // 关闭数据库连接 mysqli_close($conn);
-
后台页面:
<?php if ($_COOKIE['username'] == 'admin' and $_COOKIE['password'] == 'sjjjer') { echo "欢迎来到后台!"; } else { header("location:login.php?error=1"); }
-
ok,我们来测试一下这段demo:
通过这段简单的demo实现了Cookie鉴权,但有没有发现什么问题呢?这段Cookie是由表单提交正确的username和password所生成的,一旦Cookie泄露,攻击者也就顺势得知了用户的用户名&密码。即使不由用户名&密码来生成Cookie,但由于Cookie的可读,攻击者也很容易伪造Cookie。
综上,虽然Cookie解决掉了访问受限页面时身份鉴权的问题,但Cookie自身却仍存在安全问题,那有没有既实现身份鉴权又相对安全的做法呢? → Session-Cookie鉴权。 -
-
Session-Cookie鉴权
Session-Cookie的基本流程同Cookie,只不过由服务端返回给浏览器的并非所生成的Cookie值内容,而是Session ID,当浏览器下次请求受限页面时会携带其所存储的Session ID值。-
基于Session-Cookie的身份认证逻辑:
<?php // 引入数据库配置文件 include 'db_config.php'; // 开启 session session_start(); // 连接数据库 $conn = mysqli_connect(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_NAME); // 获取表单所提交的 username password $username = $_POST["username"]; $password = $_POST["password"]; // 判断获取到的 username password 是否在数据库中有所记录 $sql = "SELECT * FROM users WHERE username = '$username' and password = '$password'"; // 将查询结果存储至 $result 中 $result = mysqli_query($conn, $sql); // 获取 $result 中的行数并判断,也就是 $sql 所获取结果的行数 if (mysqli_num_rows($result) > 0) { $_SESSION['username'] = $username; $_SESSION['password'] = $password; header('Location: admin.php'); exit(); }else{ header('Location: login.php?error=1'); exit(); } // 关闭数据库连接 mysqli_close($conn);
-
后台页面:
<?php session_start(); if ($_SESSION['username'] == 'admin' and $_SESSION['password'] == 'sjjjer') { echo "欢迎来到后台!"; } else { header("location:login.php?error=1"); }
-
老样子,来测试一下该demo:
由于Session ID的不可读&随机性,导致攻击者几乎不可能伪造。既解决了身份鉴权,又相较于Cookie更加安全。虽然无法伪造Session ID,但XSS、CSRF等窃取&利用Cookie的攻击仍然有效,即使不伪造身份,也仍有重放攻击(也就是爆破)的手段,直接获取用户名&密码。
那么开发者针对重放攻击,有没有更好的应对手段呢? → 加Token。 -
-
Token-Session鉴权
用户在每一次登陆提交数据时会携带随机生成的Token,执行登录操作后会将携带的Token值刷新,若此时用户仍使用原Token提交登录数据则会被直接拒绝,避免了重放攻击。身份鉴权仍使用Session-Cookie,只是这里加了Token防爆破而已,所以这里的Token仅是一种防爆破的手段,而非一种新的鉴权方式。-
登录表单需要添加生成&提交Token的代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>登录</title> <link rel="stylesheet" href="styles.css"> </head> <body> <?php // 随机生成Token,并将其值存储至Session中 session_start(); $_SESSION['token'] = bin2hex(random_bytes(32)); ?> <div class="login-container"> <h2>后台登录</h2> <!-- <form action="BasiccheckDemo1.php" method="POST">--> <!-- <form action="CookiecheckDemo2.php" method="POST">--> <!-- <form action="SessioncheckDemo3.php" method="POST">--> <form action="TokencheckDemo4.php" method="POST"> <div class="form-group"> <label for="username">用户名</label> <input type="text" id="username" name="username" required> </div> <div class="form-group"> <label for="password">密码</label> <input type="password" id="password" name="password" required> </div> <button type="submit" class="login-btn">登录</button> <!-- 隐藏字段用于提交Token --> <input type="hidden" id="token" name="token" value="<?php echo $_SESSION['token']; ?>"> </form> </div> <?php if (isset($_GET['error'])){ echo "<script>alert('用户名或密码错误!');</script>"; echo "<script> // 使 URL 仅保留原路径而不携带任何参数 history.replaceState(null, null, window.location.pathname); </script>"; } ?> </body> </html>
-
在原有身份认证逻辑基础上,添加对Token的认证&刷新:
<?php // 引入数据库配置文件 include 'db_config.php'; // 开启 session session_start(); // 连接数据库 $conn = mysqli_connect(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_NAME); // 获取表单所提交的 username password token $username = $_POST["username"]; $password = $_POST["password"]; $token = $_POST["token"]; // 判断获取到的 username password 是否在数据库中有所记录 $sql = "SELECT * FROM users WHERE username = '$username' and password = '$password'"; // 将查询结果存储至 $result 中 $result = mysqli_query($conn, $sql); // 验证 token username password if (empty($token) || $token !== $_SESSION['token']) { echo "FBI, Don't Hack!!!"; header('Location: login.php'); } elseif (mysqli_num_rows($result) > 0) { $_SESSION['username'] = $username; $_SESSION['password'] = $password; header('Location: admin.php'); exit(); } else { $_SESSION['token'] = bin2hex(random_bytes(32)); header('Location: login.php?error=1'); exit(); } // 关闭数据库连接 mysqli_close($conn);
-
后台页面同上。
-
测试demo:
至此!PHP中所常用的身份鉴权技术介绍完毕,累死我了~
-
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现