在Symfony项目中实现JWT认证,LexikJWTBundle是最常用的官方推荐组件,它能快速完成JWT令牌的生成、校验、过期处理等核心能力,适配API接口的无状态认证需求。

环境准备与Bundle安装
首先确保项目已经安装Symfony 4.4及以上版本,并且已经配置好Composer依赖管理工具。执行以下命令安装LexikJWTBundle:
composer require lexik/jwt-authentication-bundle
安装完成后,Bundle会自动注册到Symfony的容器中,接下来需要生成JWT签名所需的密钥对。
生成JWT签名密钥
LexikJWTBundle使用非对称加密算法生成和校验JWT令牌,需要生成私钥和公钥文件。执行以下命令生成密钥,过程中会提示设置私钥密码,建议设置复杂度较高的密码:
php bin/console lexik:jwt:generate-keypair
命令执行后会在项目的config/jwt目录下生成private.pem和public.pem两个文件,分别对应私钥和公钥,注意不要把私钥文件提交到公共代码仓库。
核心配置说明
打开config/packages/lexik_jwt_authentication.yaml配置文件,调整核心参数:
lexik_jwt_authentication:
secret_key: '%env(resolve:JWT_SECRET_KEY)%' # 私钥路径,默认已配置
public_key: '%env(resolve:JWT_PUBLIC_KEY)%' # 公钥路径,默认已配置
pass_phrase: '%env(JWT_PASSPHRASE)%' # 私钥密码,默认已配置
token_ttl: 3600 # 令牌有效期,单位秒,默认1小时
user_identity_field: email # 用于标识用户的字段,默认是username,可根据需求修改
同时需要在.env文件中补充对应的环境变量,避免密钥路径和密码硬编码:
JWT_SECRET_KEY=config/jwt/private.pem JWT_PUBLIC_KEY=config/jwt/public.pem JWT_PASSPHRASE=你设置的私钥密码
配置安全规则
打开config/packages/security.yaml,添加JWT认证相关的安全配置:
security:
enable_authenticator_manager: true
providers:
app_user_provider:
entity:
class: AppEntityUser
property: email # 与JWT配置中的user_identity_field对应
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
api:
pattern: ^/api/
stateless: true
jwt: ~ # 启用JWT认证
access_control:
- { path: ^/api/login, roles: PUBLIC_ACCESS } # 登录接口允许匿名访问
- { path: ^/api/, roles: ROLE_USER } # 其他API接口需要认证
实现登录获取令牌接口
创建登录控制器,接收用户账号密码,验证通过后生成JWT令牌返回:
<?php
namespace AppController;
use SymfonyBundleFrameworkBundleControllerAbstractController;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpFoundationJsonResponse;
use SymfonyComponentRoutingAnnotationRoute;
use SymfonyComponentSecurityCoreExceptionBadCredentialsException;
use LexikBundleJWTAuthenticationBundleServicesJWTTokenManagerInterface;
use SymfonyComponentSecurityCoreUserUserProviderInterface;
class AuthController extends AbstractController
{
#[Route('/api/login', name: 'api_login', methods: ['POST'])]
public function login(
Request $request,
UserProviderInterface $userProvider,
JWTTokenManagerInterface $jwtManager
): JsonResponse {
$data = json_decode($request->getContent(), true);
$email = $data['email'] ?? '';
$password = $data['password'] ?? '';
try {
// 加载用户
$user = $userProvider->loadUserByIdentifier($email);
// 校验密码,实际项目中建议使用Symfony的密码编码器
if (!password_verify($password, $user->getPassword())) {
throw new BadCredentialsException('密码错误');
}
// 生成JWT令牌
$token = $jwtManager->create($user);
return new JsonResponse([
'code' => 200,
'message' => '登录成功',
'data' => [
'token' => $token,
'expire_in' => 3600
]
]);
} catch (Exception $e) {
return new JsonResponse([
'code' => 401,
'message' => '认证失败:' . $e->getMessage()
], 401);
}
}
}
令牌校验与接口访问
访问需要认证的API接口时,需要在请求头中添加Authorization字段,格式为Bearer 令牌内容。LexikJWTBundle会自动校验令牌的有效性,包括是否过期、签名是否正确等。
如果令牌无效,会返回401状态码和对应的错误信息,例如令牌过期会返回:
{
"code": 401,
"message": "JWT Token expired"
}
常见问题排查
- 令牌生成失败:检查私钥路径、私钥密码是否正确,私钥文件是否有读取权限
- 令牌校验失败:检查公钥路径是否正确,公钥文件是否和生成令牌的私钥匹配
- 用户加载失败:检查security配置中的用户提供者是否正确,用户标识字段是否和JWT配置一致
SymfonyJWT认证LexikJWTBundleAPI安全修改时间:2026-07-16 04:33:27