news 2026/1/30 3:52:54

php Token 主流实现方案详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
php Token 主流实现方案详解
Token 机制广泛应用于身份验证、防止 CSRF 攻击、接口鉴权等场景。在 PHP 中,主流实现方案均围绕生成唯一标识 + 存储验证 + 有效期控制三大核心思路展开。本文梳理了 4 种主流实现方式,便于快速选型和实践。

方案 1:基于 Session 的 Token 实现

核心原理

利用 PHP 内置 Session 机制,将 Token 存储在服务端 Session 中,客户端仅保存 SessionID(通常通过 Cookie)。每次请求时,服务端验证 Token 是否匹配。

实现代码

<?php // 初始化Session session_start(); /** * 生成并存储Token */ function generateSessionToken() { $token = bin2hex(random_bytes(16)); $_SESSION['csrf_token'] = $token; $_SESSION['csrf_token_expire'] = time() + 3600; // 1小时有效期 return $token; } /** * 验证Session Token */ function verifySessionToken($token) { if (!isset($_SESSION['csrf_token']) || !isset($_SESSION['csrf_token_expire'])) { return false; } if (time() > $_SESSION['csrf_token_expire']) { unset($_SESSION['csrf_token'], $_SESSION['csrf_token_expire']); return false; } $isValid = hash_equals($_SESSION['csrf_token'], $token); if ($isValid) { unset($_SESSION['csrf_token'], $_SESSION['csrf_token_expire']); } return $isValid; } // 示例 $token = generateSessionToken(); echo '<input type="hidden" name="csrf_token" value="'.$token.'">'; if ($_SERVER['REQUEST_METHOD'] === 'POST') { $clientToken = $_POST['csrf_token'] ?? ''; if (verifySessionToken($clientToken)) { echo 'Token验证通过,执行业务逻辑'; } else { echo 'Token无效或已过期'; } } ?>

优缺点

优点

缺点

实现简单,依赖 PHP 原生 Session

依赖 Cookie,客户端禁用 Cookie 则失效

Token 存储在服务端,安全性高

分布式部署需配置 Session 共享,如 Redis

支持服务端主动销毁 Token

占用服务器内存(Session 默认存储在文件/内存)


方案 2:基于 JWT(JSON Web Token)的 Token 实现

核心原理

JWT 是一种无状态Token 方案,由 Header、Payload、Signature 三部分组成。Token 存储于客户端(如 LocalStorage/Cookie),服务端仅通过签名校验其合法性和完整性。

前置条件

需安装 JWT 扩展,推荐使用 firebase/php-jwt:
composer require firebase/php-jwt

实现代码

<?php require 'vendor/autoload.php'; use Firebase\JWT\JWT; use Firebase\JWT\Key; $secretKey = 'your_strong_secret_key'; $algorithm = 'HS256'; /** * 生成JWT Token */ function generateJwtToken($payload = []) { global $secretKey, $algorithm; $defaultPayload = [ 'iat' => time(), 'exp' => time() + 3600, ]; $payload = array_merge($defaultPayload, $payload); return JWT::encode($payload, $secretKey, $algorithm); } /** * 验证JWT Token */ function verifyJwtToken($token) { global $secretKey, $algorithm; try { $decoded = JWT::decode($token, new Key($secretKey, $algorithm)); return (array)$decoded; } catch (Exception $e) { echo 'Token验证失败:' . $e->getMessage(); return false; } } // 示例 $userPayload = ['uid' => 1001, 'username' => 'test_user']; $jwtToken = generateJwtToken($userPayload); echo '生成的JWT Token:' . $jwtToken . '<br>'; $clientToken = $_GET['token'] ?? ''; $decodedData = verifyJwtToken($clientToken); if ($decodedData) { echo 'Token验证通过,用户ID:' . $decodedData['uid']; } else { echo 'Token无效'; } ?>

优缺点

优点

缺点

无状态,分布式友好

Token 无法主动销毁,仅能等过期(可用黑名单弥补)

支持跨域、跨平台

负载信息 Base64 编码,不可存储敏感数据

传输体积小,可自定义数据

密钥泄露风险高,需严格保管

不依赖 Cookie,兼容性好

过期时间固定,需重新签发才能调整


方案 3:基于 Redis 的 Token 实现

核心原理

Token 作为 Key,用户信息/过期时间作为 Value 存储在 Redis。利用 Redis 过期键特性自动管理 Token 有效期,验证时查询 Redis 是否存在该 Token 且未过期。

前置条件

需安装 PHP Redis 扩展,并配置 Redis 连接。

实现代码

<?php function initRedis() { $redis = new Redis(); try { $redis->connect('127.0.0.1', 6379); // $redis->auth('your_redis_password'); return $redis; } catch (Exception $e) { echo 'Redis连接失败:' . $e->getMessage(); return null; } } function generateRedisToken($uid, $expire = 3600) { $redis = initRedis(); if (!$redis) return false; $token = md5($uid . time() . random_bytes(16)); $tokenKey = 'token:' . $token; $redis->setex($tokenKey, $expire, $uid); return $token; } function verifyRedisToken($token) { $redis = initRedis(); if (!$redis) return false; $tokenKey = 'token:' . $token; $uid = $redis->get($tokenKey); if ($uid) { $redis->expire($tokenKey, 3600); // 滑动有效期 return (int)$uid; } return false; } function destroyRedisToken($token) { $redis = initRedis(); if (!$redis) return false; $tokenKey = 'token:' . $token; return $redis->del($tokenKey) > 0; } // 示例 $token = generateRedisToken(1001); echo 'Redis Token:' . $token . '<br>'; $clientToken = $_POST['token'] ?? ''; $uid = verifyRedisToken($clientToken); if ($uid) { echo 'Token验证通过,用户ID:' . $uid; } else { echo 'Token无效或已过期'; } // destroyRedisToken($clientToken); ?>

优缺点

优点

缺点

支持分布式、集群部署

依赖 Redis,增加系统复杂度

可主动销毁 Token,安全性高

Redis 性能或容灾需关注

支持滑动有效期

需处理 Redis 连接异常,代码需容错

不依赖 Cookie,兼容性好

性能略低于 Session/JWT(需网络 IO)


方案 4:基于数据库(MySQL)的 Token 实现

核心原理

将 Token、用户ID、创建/过期时间、状态等信息存储在 MySQL。验证时查询数据库,检查 Token 是否存在、未过期且状态有效。

数据库表结构

CREATE TABLE `user_token` ( `id` int(11) NOT NULL AUTO_INCREMENT, `uid` int(11) NOT NULL COMMENT '用户ID', `token` varchar(64) NOT NULL COMMENT '令牌值', `create_time` int(11) NOT NULL COMMENT '创建时间(时间戳)', `expire_time` int(11) NOT NULL COMMENT '过期时间(时间戳)', `status` tinyint(1) NOT NULL DEFAULT 1 COMMENT '1-有效 0-无效', PRIMARY KEY (`id`), UNIQUE KEY `idx_token` (`token`), KEY `idx_uid` (`uid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户令牌表';

实现代码

<?php $dbConfig = [ 'host' => '127.0.0.1', 'user' => 'root', 'password' => 'your_db_password', 'dbname' => 'test', 'charset' => 'utf8mb4' ]; function initDb() { global $dbConfig; try { $dsn = "mysql:host={$dbConfig['host']};dbname={$dbConfig['dbname']};charset={$dbConfig['charset']}"; $pdo = new PDO($dsn, $dbConfig['user'], $dbConfig['password']); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); return $pdo; } catch (PDOException $e) { echo '数据库连接失败:' . $e->getMessage(); return null; } } function generateDbToken($uid, $expire = 3600) { $pdo = initDb(); if (!$pdo) return false; $token = hash('sha256', $uid . time() . random_bytes(32)); $createTime = time(); $expireTime = $createTime + $expire; $sql = "INSERT INTO user_token (uid, token, create_time, expire_time, status) VALUES (:uid, :token, :create_time, :expire_time, 1)"; $stmt = $pdo->prepare($sql); $stmt->bindParam(':uid', $uid, PDO::PARAM_INT); $stmt->bindParam(':token', $token, PDO::PARAM_STR); $stmt->bindParam(':create_time', $createTime, PDO::PARAM_INT); $stmt->bindParam(':expire_time', $expireTime, PDO::PARAM_INT); return $stmt->execute() ? $token : false; } function verifyDbToken($token) { $pdo = initDb(); if (!$pdo) return false; $now = time(); $sql = "SELECT uid FROM user_token WHERE token = :token AND status = 1 AND expire_time > :now LIMIT 1"; $stmt = $pdo->prepare($sql); $stmt->bindParam(':token', $token, PDO::PARAM_STR); $stmt->bindParam(':now', $now, PDO::PARAM_INT); $stmt->execute(); $result = $stmt->fetch(PDO::FETCH_ASSOC); if ($result) { return (int)$result['uid']; } return false; } function destroyDbToken($token) { $pdo = initDb(); if (!$pdo) return false; $sql = "UPDATE user_token SET status = 0 WHERE token = :token"; $stmt = $pdo->prepare($sql); $stmt->bindParam(':token', $token, PDO::PARAM_STR); return $stmt->execute() && $stmt->rowCount() > 0; } // 示例 $token = generateDbToken(1001); echo '数据库Token:' . $token . '<br>'; $clientToken = $_SERVER['HTTP_TOKEN'] ?? ''; $uid = verifyDbToken($clientToken); if ($uid) { echo 'Token验证通过,用户ID:' . $uid; } else { echo 'Token无效或已过期'; } // destroyDbToken($clientToken); ?>

优缺点

优点

缺点

支持复杂 Token 管理(如批量禁用、查询记录)

数据库 IO 性能低于 Redis/Session,高并发下易成瓶颈

数据持久化,方便追溯

需手动清理过期 Token,表数据易膨胀

可扩展字段,便于审计

分布式部署需考虑主从同步

支持主动销毁 Token

代码复杂度高,需处理事务、异常等


各方案对比汇总表

对比维度

Session Token

JWT Token

Redis Token

数据库 Token

存储位置

服务端(文件/内存)

客户端

服务端(Redis)

服务端(MySQL)

状态特性

有状态

无状态

有状态

有状态

分布式支持

需 Session 共享

天然支持

Redis 集群

主从同步/分库分表

主动销毁

支持

不支持(需黑名单)

支持

支持

性能

极高

复杂度

适用场景

小型项目、CSRF 防护

前后端分离、无状态服务

中大型项目、分布式

审计、复杂权限、低并发

安全性


总结与选型建议

  1. 选型核心原则
  • 小型单节点项目:优先选用 Session Token(实现简单)。
  • 前后端分离/跨域场景:优先选用 JWT Token(无状态,易于扩展)。
  • 中大型分布式项目:优先选用 Redis Token(性能与灵活性兼具)。
  • 需审计/复杂管理场景:可选 数据库 Token(持久化与扩展性强)。
  1. 安全性建议
  • 所有 Token 建议通过 HTTPS 传输,防止明文泄露。
  • JWT 密钥需定期更换,且严密保管。
  • Session/Redis/数据库 Token 建议设置合理有效期,验证后一次性销毁(CSRF 场景)或滑动刷新(登录态场景)。
  1. 混合使用场景
  • 可结合 JWT + Redis,实现“无状态 + 可销毁”机制:JWT 存储基础信息,Redis 存储 JWT 黑名单,兼顾性能与灵活性。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/28 17:44:33

「大模型学习黄金书单」认真啃完这些书,一条线速通大模型

说句实在的&#xff0c;很多人以为学大模型就是搞点提示词、调个 API&#xff0c;就能搞定一切。但真想“弄懂它”&#xff0c;甚至“做出点东西”来&#xff0c;不啃几本靠谱的书&#xff0c;真的不行。 我一开始也是刷了一堆教程&#xff0c;收藏了几十个 AI 工具帖&#xf…

作者头像 李华
网站建设 2026/1/28 17:43:48

用Notion管理测试用例?2026年高阶测试员都在用

在软件测试领域&#xff0c;测试用例管理是保障产品质量的核心环节&#xff0c;涉及需求分析、用例设计、执行跟踪和缺陷修复的全流程。传统工具如Excel或Jira常面临用例散乱、更新滞后和协作低效的痛点。进入2026年&#xff0c;Notion以其灵活的数据库、AI智能集成和高度可定制…

作者头像 李华
网站建设 2026/1/28 17:43:17

Sa-Token 如何忽略鉴权?三种方式让你灵活放行接口!

视频看了几百小时还迷糊&#xff1f;关注我&#xff0c;几分钟让你秒懂&#xff01; 在使用 Sa-Token 做权限控制时&#xff0c;我们通常希望&#xff1a; /login、/register、/health 等接口 无需登录即可访问&#xff1b;Swagger 文档、静态资源、验证码接口 跳过鉴权&#…

作者头像 李华
网站建设 2026/1/28 17:37:45

NSCAT 2 级海洋风矢量地球物理数据记录

NSCAT Level 2 Ocean Wind Vector Geophysical Data Record 简介 美国国家航空航天局散射计&#xff08;NSCAT&#xff09;二级海洋风矢量数据以 50 公里风矢量网格&#xff08;WVC&#xff09;幅宽呈现&#xff0c;包含每日上升和下降轨道的数据。风矢量的精度在 2 米/秒&am…

作者头像 李华