身份鉴权(PHP)

news/2025/1/11 0:07:15/文章来源:https://www.cnblogs.com/sjjjjer/p/18664965

免责声明:本文章仅用于交流学习,因文章内容而产生的任何违法&未授权行为,与文章作者无关!!!
附:完整笔记目录~
ps:本人小白,笔记均在个人理解基础上整理,若有错误欢迎指正!

1.2 🐘身份鉴权(PHP)

  1. 引子:上一章主要对PHP中全局变量做了介绍,其中$_COOKIE$_SESSION常常在身份鉴权中被使用。而本章则是由代码具体聊聊在PHP Web中开发者所常使用的身份鉴权方式。
    这里再简单介绍一下身份鉴权,确认用户&系统在访问某受限资源时,身份是否合法。若想具体了解各鉴权方式的工作流程&优缺点,可参考:https://www.cnblogs.com/sjjjjer/p/18603336

  2. 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><?phpif (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;
      }
      
    • 效果展示
      image-20250110125935671
      貌似也没那么美观哈哈~

    • 接下来再创建一个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
      image-20250110160305225

    由上述案例可知,只有当post所提交的用户名密码正确时,才会跳转至后台页面。可后台页面往往有很多,为了防止其他用户也能访问后台,难道要在每一个后台页面前都要加上判断用户名&密码是否正确的逻辑吗?于开发者&用户而言,很麻烦也没有必要,因此出现了Session-Cookie鉴权。

  3. 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:
      image-20250110193349610

    通过这段简单的demo实现了Cookie鉴权,但有没有发现什么问题呢?这段Cookie是由表单提交正确的username和password所生成的,一旦Cookie泄露,攻击者也就顺势得知了用户的用户名&密码。即使不由用户名&密码来生成Cookie,但由于Cookie的可读,攻击者也很容易伪造Cookie。
    综上,虽然Cookie解决掉了访问受限页面时身份鉴权的问题,但Cookie自身却仍存在安全问题,那有没有既实现身份鉴权又相对安全的做法呢? → Session-Cookie鉴权。

  4. 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:
      image-20250110204530341

    由于Session ID的不可读&随机性,导致攻击者几乎不可能伪造。既解决了身份鉴权,又相较于Cookie更加安全。虽然无法伪造Session ID,但XSS、CSRF等窃取&利用Cookie的攻击仍然有效,即使不伪造身份,也仍有重放攻击(也就是爆破)的手段,直接获取用户名&密码。
    那么开发者针对重放攻击,有没有更好的应对手段呢? → 加Token。

  5. 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><?phpif (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:
      image-20250110234340689

    至此!PHP中所常用的身份鉴权技术介绍完毕,累死我了~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/867431.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UE4.27, 揣摩源码, 网络同步 (三) RPC

6. RPC6.1. RPC是网络同步的一部分,全称Remote Procedure Call。属性同步只能从服务端向客户端单向传递信息,而RPC可以双向传递消息  6.2. 类型6.2.1. Server调用,Actor所属的Client执行    6.2.2. Client调用,Server执行    6.2.3. Server调用,Server和所…

Discharging Method

Firstly, we introduce Euler Formula.When we use Euler formula, we often need its transformations.Secondly, we design some discharging rules based on Euler Formula.Finally, we give the principle of Discharging Method in proofs.

2024.12.16(SpringBoot知识点总结)

4.2 配置文件与配置类的属性映射方式 4.2.1 使用注解@Value映射 我们可以通过@Value注解将配置文件中的值映射到一个Spring管理的Bean的字段上 例如: application.properties配置如下: person: name: zhangsan age: 18 1 2 3 或者,application.yml配置如下: person: name: …

2024.12.7(SpringBoot知识点总结)

2.2.2 SpringBoot代码解析 @SpringBootApplication:标注SpringBoot的启动类,该注解具备多种功能(后面详细剖析) SpringApplication.run(MySpringBootApplication.class) 代表运行SpringBoot的启动类,参数为SpringBoot启动类的字节码对象 2.2.3 SpringBoot工程热部署 我们在…

python SQLAlchemy ORM——从零开始学习 04 如何过滤(筛选)数据库中的数据

04 如何过滤(筛选)数据库中的数据 从数据库中获筛选数据主要应用以下几个接口:filter、filter_by、以及 where。前两个在 02已经展开说过,先展开说where接口 前情提要:依赖03提及的model【本质上就是数据库的链接,有可忽视】 当前的数据库表内容如下,仅作例子,不相同根…

[Linux] 包管理器之【APT】

序续:《[Linux] Linux中安装软件的方式? - 博客园/千千寰宇》 《[Linux] 包管理器之综述【RPM/DPKG|YUM/APT】 - 博客园/千千寰宇》概述:包管理器 APTAPT:Advanced Packaging Tool(现名)解释: Advanced Packaging Tool(apt),作为 原始包管理器DPKG的前端包管理工具(…

2024.11.7(spring boot 创建数据库)

然后搭建四层架构 controller,mapper,pojo,service创建mapper的映射文件

2024.11.8(spring boot创建数据库)

三、连接数据库 1.编写文件 在resources包下找到application.properties,将如下代码写入: spring.datasource.username=root spring.datasource.password=admin spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&cha…

2024.11.9(spring boot创建数据库)

pojo层实体类里的属性要与数据表一一对应;查询所有用户是要返回多个User,所以用List; Service层先用@Autowired注入userMapper; 然后声明方法;

django python manage.py报错TimeoutError: [WinError 10060] A connection attempt failed

diango python manage.py报错 TimeoutError: [WinError 10060] A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond 加个代理即可

4. gazebo仿真环境中添加robotiq 2f 140的gripper_controller控制器

原文地址: gazebo仿真环境中添加robotiq 2f 140的gripper_controller控制器 gazebo仿真环境中添加robotiq 2f 140的gripper_controller控制器搭建环境: ubuntu: 20.04ros: Noneticsensor: robotiq_ft300gripper: robotiq_2f_140_gripperUR: UR3reasense: D435i 通过下面几篇博…

tomcat9.0下载安装及配置图文教程

下载 官网:http://tomcat.apache.org/ 选择下载64-Bit Windows zip(Win64)2.解压到任意一个盘,如,D:\apache-tomcat-9.0.98 3.设置环境变量 CATALINA_HOME:D:\apache-tomcat-9.0.98 找到系统变量Path,添加:%CATALINA_HOME%\bin验证是否配置成功 进入Windows命令行窗口,…