
在构建无状态 API 时,JWT 是一种流行的认证机制。其基本流程如下:
为了在 Symfony 5.3 中实现上述流程,我们需要配置 security.yaml 文件,并创建一个自定义的 JWT 认证器。
在认证控制器(例如 AuthController)中,当用户成功登录后,我们使用 Firebase\JWT\JWT 库来生成一个 JWT,并将其作为 JSON 响应返回给客户端。
<?php
// 部分 AuthController 代码示例
// ...
use Symfony\Component\HttpFoundation\JsonResponse;
use Firebase\JWT\JWT;
class AuthController extends AbstractController
{
// ...
public function authenticate(Request $request, ContainerBagInterface $params): JsonResponse
{
// 假设这里已经完成了用户凭证验证,并获取到用户ID
$userId = 123; // 示例用户ID
// 构造 JWT payload
$payload = [
'iss' => 'your-api-domain.com', // 签发者
'aud' => 'your-api-client', // 受众
'iat' => time(), // 签发时间
'exp' => time() + 3600, // 过期时间(1小时)
'sub' => $userId // 主题:用户ID
];
// 从参数中获取 JWT 密钥
$jwtSecret = $params->get('jwt_secret');
// 使用 HS256 算法生成 JWT
$jwt = JWT::encode($payload, $jwtSecret, 'HS256');
$body = [
'auth_token' => $jwt,
];
return new JsonResponse($body, 201);
}
}请确保您的 services.yaml 或 parameters.yaml 中定义了 jwt_secret 参数,例如:
# config/services.yaml 或 config/packages/parameters.yaml
parameters:
jwt_secret: '%env(JWT_SECRET)%' # 建议从环境变量获取security.yaml 是 Symfony 安全配置的核心,它定义了防火墙、认证提供者和访问控制规则。正确配置此文件是实现 JWT 认证的关键。
# config/packages/security.yaml
security:
enable_authenticator_manager: true # Symfony 5.3 推荐使用此管理器
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
encoders: # 兼容旧版 Symfony 认证器
App\Entity\ATblUsers:
algorithm: bcrypt
providers:
# 这里可以使用您的用户提供者,例如从数据库加载用户
# 示例中使用内存用户,实际应用中应替换为您的用户实体提供者
users_in_memory: { memory: null }
# 例如:
# app_user_provider:
# entity: { class: App\Entity\ATblUsers, property: email }
firewalls:
dev: # 开发环境调试防火墙,不进行安全检查
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main: # 主防火墙,处理大部分API请求
guard: # Symfony 5.3 仍然支持 Guard 认证器
authenticators:
- App\Security\JwtAuthenticator # 注册我们的自定义认证器
lazy: true # 惰性加载用户,按需加载
provider: users_in_memory # 指定用户提供者
stateless: true # 声明此防火墙是无状态的,不使用会话
access_control:
# 允许所有用户访问认证接口,无需任何凭证
- { path: ^/authenticate, roles: PUBLIC_ACCESS }
# 对所有其他路径强制要求完全认证(即必须提供有效JWT)
- { path: ^/, roles: IS_AUTHENTICATED_FULLY }关键配置点解析:
JwtAuthenticator 继承自 AbstractGuardAuthenticator,它负责从请求中提取 JWT、验证其有效性并加载相应的用户。
<?php
// src/Security/JwtAuthenticator.php
namespace App\Security;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Firebase\JWT\JWT;
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
class JwtAuthenticator extends AbstractGuardAuthenticator
{
private $em;
private $params;
public function __construct(EntityManagerInterface $em, ContainerBagInterface $params)
{
$this->em = $em;
$this->params = $params;
}
/**
* 当认证失败时,此方法会被调用,返回一个 JSON 响应。
*/
public function start(Request $request, AuthenticationException $authException = null): JsonResponse
{
$body = [
'message' => 'Authentication Required',
];
return new JsonResponse($body, Response::HTTP_UNAUTHORIZED);
}
/**
* 判断当前请求是否支持此认证器。
* 如果请求头中包含 'Authorization',则表示支持。
*/
public function supports(Request $request): bool
{
return $request->headers->has('Authorization');
}
/**
* 从请求中获取认证凭证(JWT)。
*/
public function getCredentials(Request $request)
{
// 提取 Bearer Token
$authorizationHeader = $request->headers->get('Authorization');
if (str_starts_with($authorizationHeader, 'Bearer ')) {
return str_replace('Bearer ', '', $authorizationHeader);
}
return null; // 如果不是 Bearer token,返回 null
}
/**
* 根据凭证加载用户。
* 在这里解码 JWT 并通过其中的 'sub'(用户ID)查找用户。
*/
public function getUser($credentials, UserProviderInterface $userProvider)
{
if (null === $credentials) {
return null;
}
try {
// 获取 JWT 密钥
$jwtSecret = $this->params->get('jwt_secret');
// 解码 JWT
$jwt = (array) JWT::decode($credentials, new \Firebase\JWT\Key($jwtSecret, 'HS256'));
// 假设 'sub' 字段存储用户ID
if (!isset($jwt['sub'])) {
throw new AuthenticationException('JWT payload does not contain user ID (sub).');
}
// 从数据库中查找用户实体
// 假设您的用户实体类为 App\Entity\ATblUsers
return $this->em->getRepository('App\Entity\ATblUsers')->find($jwt['sub']);
} catch (\Exception $exception) {
// JWT 解码失败(如签名无效、过期等)或用户不存在
throw new AuthenticationException($exception->getMessage());
}
}
/**
* 检查凭证是否有效。
* 对于 JWT,通常在 getUser() 中已经完成了所有验证,此方法可以留空或进行额外检查。
*/
public function checkCredentials($credentials, UserInterface $user): bool
{
// JWT 的有效性(签名、过期)已在 getUser() 中验证
// 这里可以进行额外的用户状态检查,例如用户是否被禁用
return true;
}
/**
* 认证失败时被调用,返回 JSON 错误响应。
*/
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): JsonResponse
{
return new JsonResponse([
'message' => 'Authentication Failed: ' . $exception->getMessage()
], Response::HTTP_UNAUTHORIZED);
}
/**
* 认证成功时被调用。
* 对于无状态 API,通常不返回任何内容。
*/
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey)
{
return null; // 继续处理请求
}
/**
* 是否支持记住我功能。对于无状态 API,通常为 false。
*/
public function supportsRememberMe(): bool
{
return false;
}
}注意: 在 getUser 方法中,JWT::decode 的第二个参数在 firebase/php-jwt 6.0+ 版本中已改为 \Firebase\JWT\Key 对象。请根据您安装的 firebase/php-jwt 版本进行调整。上述代码已更新为新版本兼容写法。
通过以上配置和自定义认证器的实现,我们成功地在 Symfony 5.3 应用中建立了基于 JWT 的无状态 API 认证系统。核心在于通过 security.yaml 中的 firewalls 和 access_control 定义认证机制和访问权限,并利用 JwtAuthenticator 负责 JWT 的解析和用户加载。这确保了只有持有有效 JWT 的请求才能访问受保护的 API 资源,从而提升了 API 的安全性。
以上就是Symfony 5.3 中使用 JWT 实现 API 认证与访问控制的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号