OAuth 2.0 和 JWT 授权在 PHP 上的应用:完整实践指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

OAuth 2.0 和 JWT 在 PHP 中的介绍

现代 Web 应用程序正越来越多地从传统的会话认证转向更灵活、可扩展的解决方案。两个关键协议——OAuth 2.0 和 JWT(JSON Web 令牌)——已成为 REST API、移动应用程序和微服务架构中授权的事实标准。在本文中,我们将通过实际示例,讲解如何使用现代库和最佳安全实践在 PHP 中实现 OAuth 2.0 和 JWT 授权。

您将学习如何配置授权服务器、签发和验证 JWT 令牌、组织刷新令牌的发放以及保护您的 API 端点。所有代码示例均可直接在您的项目中使用。



OAuth 2.0 协议基础

OAuth 2.0 是一种授权协议,允许应用程序在无需传递用户凭证的情况下,获取对用户资源的有限访问权限。在 PHP 应用程序的上下文中,OAuth 2.0 通常通过授权码授权(Authorization Code Grant)或针对自有服务的密码授权(Password Grant)来实现。



OAuth 2.0 中的关键角色

  • 资源所有者 — 拥有数据的用户
  • 客户端 — 请求访问的应用程序(例如您的 PHP 前端)
  • 授权服务器 — 签发令牌的服务器
  • 资源服务器 — 提供受保护资源的服务器(您的 API)


通过授权码授权获取令牌的流程

  1. 用户导航到授权页面
  2. 登录后,用户被重定向回应用程序,并附带一个临时授权码
  3. PHP 服务器用该授权码交换 access_token 和 refresh_token
  4. 所有后续对 API 的请求都包含 Authorization: Bearer <access_token> 头


使用 firebase/php-jwt 库在 PHP 中实现 JWT

为了在 PHP 中处理 JWT,我们将使用流行的 firebase/php-jwt 库。通过 Composer 安装它:

composer require firebase/php-jwt


生成 JWT 令牌

创建一个函数来签发带有有效载荷(claims)的访问令牌:

<?phpuse Firebase\\JWT\\JWT;use Firebase\\JWT\\Key;

function generateAccessToken(int $userId, string $email): string { $secretKey = 'your-256-bit-secret-key-here'; $issuedAt = time(); $expirationTime = $issuedAt + 3600; // 1 小时

$payload = [ 'iss' => 'pythonlib.ru', 'iat' => $issuedAt, 'exp' => $expirationTime, 'sub' => $userId, 'email' => $email, 'roles' => ['user'] ];

return JWT::encode($payload, $secretKey, 'HS256');}


验证 JWT 令牌

每次请求受保护资源时验证令牌的真实性:

<?phpfunction validateAccessToken(string $token): ?object {    $secretKey = 'your-256-bit-secret-key-here';    try {        $decoded = JWT::decode($token, new Key($secretKey, 'HS256'));        return $decoded;    } catch (\\Exception $e) {        // 令牌已过期、无效或签名不匹配        return null;    }}


用于验证 JWT 的中间件

一个简单的中间件示例,可与任何框架一起使用:

<?phpfunction authMiddleware(): ?object {    $headers = getallheaders();    $authHeader = $headers['Authorization'] ?? '';

if (!preg_match('/Bearer\\s(\\S+)/', $authHeader, $matches)) { http_response_code(401); echo json_encode(['error' => '未提供令牌']); exit; }

$token = $matches[1]; $user = validateAccessToken($token);

if (!$user) { http_response_code(401);

博客

书籍推荐