0

0

在 Symfony 5.3 中实现 JWT 认证与 API 访问控制

花韻仙語

花韻仙語

发布时间:2025-07-19 15:04:21

|

708人浏览过

|

来源于php中文网

原创

在 Symfony 5.3 中实现 JWT 认证与 API 访问控制

本教程详细阐述了如何在 Symfony 5.3 应用中实现基于 JWT 的 API 访问控制。文章首先介绍了 JWT 认证器的核心实现,包括令牌的获取、验证和用户加载逻辑。随后,重点讲解了如何在 security.yaml 中配置防火墙和 access_control 规则,以确保受保护的 API 路由仅允许携带有效 JWT 令牌的请求访问。通过示例代码和关键注意事项,帮助开发者构建安全的无状态 API。

1. 理解 Symfony 中的 JWT 认证流程

在 symfony 中实现 jwt(json web token)认证,核心在于创建一个自定义的认证器(authenticator)并将其配置到安全防火墙中。jwt 认证通常用于无状态 api,即服务器不维护会话状态,每次请求都通过 jwt 令牌进行认证。

一个典型的 JWT 认证流程包括以下步骤:

  1. 用户登录:用户提供凭据(如用户名和密码)进行登录。
  2. 生成 JWT:如果凭据有效,服务器生成一个 JWT 令牌并返回给客户端。
  3. 携带 JWT 访问:客户端将 JWT 令牌存储起来,并在后续的每个受保护请求中,通过 Authorization 请求头(通常是 Bearer 方案)将令牌发送到服务器。
  4. 验证 JWT:服务器接收到请求后,通过认证器解析并验证 JWT 令牌的有效性(包括签名、过期时间等)。
  5. 授权访问:如果令牌有效,服务器根据令牌中的用户信息(如用户ID、角色)授予或拒绝访问特定资源。

2. 构建 JWT 认证器 (JwtAuthenticator)

JwtAuthenticator 是 Symfony 安全组件与 JWT 令牌交互的核心。它继承自 AbstractGuardAuthenticator,并实现了多个关键方法来处理认证流程。

em = $em;
        $this->params = $params;
    }

    /**
     * 当认证失败时,此方法被调用,用于返回一个认证错误响应。
     */
    public function start(Request $request, AuthenticationException $authException = null): JsonResponse
    {
        return new JsonResponse(['message' => 'Authentication Required'], Response::HTTP_UNAUTHORIZED);
    }

    /**
     * 判断当前请求是否需要此认证器处理。
     * 如果请求头中包含 'Authorization',则返回 true。
     */
    public function supports(Request $request): bool
    {
        return $request->headers->has('Authorization');
    }

    /**
     * 从请求中提取认证凭据(即 JWT 令牌)。
     */
    public function getCredentials(Request $request)
    {
        return $request->headers->get('Authorization');
    }

    /**
     * 根据凭据(JWT 令牌)加载用户。
     * 此方法会解码 JWT,验证其签名和有效性,并从数据库中查找对应的用户。
     * 如果令牌无效或用户不存在,则抛出 AuthenticationException。
     */
    public function getUser($credentials, UserProviderInterface $userProvider)
    {
        try {
            // 移除 "Bearer " 前缀
            $credentials = str_replace('Bearer ', '', $credentials);
            // 解码 JWT,使用配置中的密钥和算法
            $jwt = (array) JWT::decode($credentials, $this->params->get('jwt_secret'), ['HS256']);
            // 根据 JWT 中的 'sub'(通常是用户ID)从数据库中查找用户
            return $this->em->getRepository('App:ATblUsers')->find($jwt['sub']);
        } catch (\Exception $exception) {
            // 解码或查找用户失败,抛出认证异常
            throw new AuthenticationException($exception->getMessage());
        }
    }

    /**
     * 检查凭据是否有效。
     * 对于 JWT 认证,令牌的有效性通常在 getUser 方法中通过 JWT::decode 完成,
     * 因此此方法通常保持为空或简单返回 true。
     */
    public function checkCredentials($credentials, UserInterface $user): bool
    {
        // JWT 令牌的有效性已在 getUser 方法中验证
        return true;
    }

    /**
     * 认证失败时被调用。
     */
    public function onAuthenticationFailure(Request $request, AuthenticationException $exception): JsonResponse
    {
        return new JsonResponse([
            'message' => $exception->getMessage()
        ], Response::HTTP_UNAUTHORIZED);
    }

    /**
     * 认证成功时被调用。
     * 对于无状态 API,此方法通常无需执行任何操作。
     */
    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey)
    {
        // 无状态 API,认证成功后无需额外操作
        return null;
    }

    /**
     * 指示是否支持 "记住我" 功能。
     * 对于无状态 JWT 认证,通常返回 false。
     */
    public function supportsRememberMe(): bool
    {
        return false;
    }
}

关键点说明:

  • __construct: 注入 EntityManagerInterface 用于数据库操作(查找用户)和 ContainerBagInterface 用于获取 jwt_secret 配置。
  • start: 当请求需要认证但没有提供凭据时,此方法返回一个 401 Unauthorized 响应。
  • supports: 检查请求头中是否存在 Authorization 字段,决定是否由当前认证器处理该请求。
  • getCredentials: 从 Authorization 请求头中提取完整的 JWT 字符串。
  • getUser: 这是 JWT 认证的核心。它首先移除 Bearer 前缀,然后使用 Firebase\JWT\JWT::decode 解码并验证 JWT 令牌。解码成功后,从令牌的 sub 字段(通常代表用户ID)中获取用户标识,并通过 EntityManager 从数据库中加载用户实体。任何解码或查找失败都会抛出 AuthenticationException。
  • checkCredentials: 对于 JWT 认证,令牌的有效性(签名、过期时间等)通常在 getUser 方法中通过 JWT::decode 完成。因此,此方法通常返回 true 即可。
  • onAuthenticationFailure / onAuthenticationSuccess: 分别处理认证失败和成功后的逻辑。对于无状态 API,成功后通常无需特殊处理,失败则返回错误信息。
  • supportsRememberMe: 无状态 API 不支持“记住我”功能,因此返回 false。

3. 配置 Symfony 安全 (security.yaml)

security.yaml 文件是 Symfony 安全配置的核心,它定义了防火墙、认证器、用户提供者和访问控制规则。正确配置 access_control 是确保 API 路由受保护的关键。

security:
    # 启用新的认证器管理器
    enable_authenticator_manager: true

    # 密码哈希器配置
    password_hashers:
        Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'

    # 实体编码器配置
    encoders:
        App\Entity\ATblUsers:
            algorithm: bcrypt

    # 用户提供者配置
    # 注意:这里使用了内存用户,但 getUser 方法实际从数据库查找用户,
    # 在生产环境中应配置为实际的数据库用户提供者。
    providers:
        users_in_memory: { memory: null }

    # 防火墙配置
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false # 开发者工具和静态资源不进行安全检查

        main:
            # 使用 Guard 认证器(在 Symfony 5.3 中仍支持,但推荐使用新的 AuthenticatorInterface)
            guard:
                authenticators:
                    - App\Security\JwtAuthenticator
            lazy: true # 懒加载用户提供者
            provider: users_in_memory # 关联用户提供者

            # 标记此防火墙为无状态,不使用 session
            stateless: true

    # 访问控制规则
    # 注意:只有第一个匹配的规则会被使用
    access_control:
        # 允许所有用户(包括匿名用户)访问 /authenticate 路由,用于登录获取 JWT
        - { path: ^/authenticate, roles: PUBLIC_ACCESS }
        # 保护所有其他路由,要求用户必须完全认证(携带有效 JWT)
        - { path: ^/, roles: IS_AUTHENTICATED_FULLY }

关键配置说明:

SoftGist
SoftGist

SoftGist是一个软件工具目录站,每天为您带来最好、最令人兴奋的软件新产品。

下载
  • enable_authenticator_manager: true: 启用 Symfony 5.1+ 引入的新认证器管理器。尽管示例中仍使用了 guard 关键字,但它会通过兼容层与新管理器协同工作。
  • firewalls.main: 定义了名为 main 的防火墙,用于保护主要应用路由。
    • guard.authenticators: - App\Security\JwtAuthenticator: 将我们自定义的 JwtAuthenticator 注册到 main 防火墙中。当请求进入此防火墙时,Symfony 会尝试使用这个认证器进行认证。
    • stateless: true: 非常重要。这告诉 Symfony 此防火墙是无状态的,它不会创建或使用会话(session)。这对于基于 JWT 的 API 是必需的,因为 JWT 本身就包含了认证信息。
  • access_control: 这是解决问题的核心! 它定义了哪些路径需要哪些角色才能访问。
    • - { path: ^/authenticate, roles: PUBLIC_ACCESS }: 这条规则允许任何人(包括未认证的用户)访问 /authenticate 路径。通常,这个路径是用于用户登录并获取 JWT 令牌的。PUBLIC_ACCESS 角色意味着不需要任何认证。
    • - { path: ^/, roles: IS_AUTHENTICATED_FULLY }: 这条规则保护了所有其他路径(^/ 匹配所有路径)。它要求访问这些路径的用户必须是“完全认证”的。这意味着用户必须通过了认证器(即提供了有效的 JWT 令牌),并且其身份已被验证。如果请求没有携带有效的 JWT,JwtAuthenticator 将会触发认证失败,并根据 start 或 onAuthenticationFailure 方法返回 401 Unauthorized 响应。

4. 总结与注意事项

通过以上配置,您的 Symfony 5.3 API 将能够正确地强制执行 JWT 认证。当一个请求到达受保护的路由时:

  1. Symfony 的安全组件会检查 access_control 规则。
  2. 如果路径匹配 ^/ 且需要 IS_AUTHENTICATED_FULLY 角色,它会尝试通过配置的认证器(JwtAuthenticator)进行认证。
  3. JwtAuthenticator 会检查 Authorization 头,提取并验证 JWT 令牌。
  4. 如果令牌有效且用户存在,请求将被允许继续处理;否则,将返回 401 Unauthorized 响应。

重要注意事项:

  • JWT 密钥管理: jwt_secret 是 JWT 签名的关键,务必妥善保管,通常存储在环境变量或 Symfony 的参数文件中(如 services.yaml 或 config/packages/framework.yaml 中定义)。
  • 用户提供者: 示例中的 providers: users_in_memory 仅用于演示。在生产环境中,您应该配置一个实际的用户提供者,如 entity 提供者,以便从数据库加载用户。JwtAuthenticator 中的 getUser 方法已经从数据库查找用户,这与 users_in_memory 存在一定程度的不匹配,但它能正常工作。
  • 错误处理: JwtAuthenticator 中的 onAuthenticationFailure 和 start 方法提供了统一的认证失败响应。您可以根据需要自定义这些响应。
  • Guard 认证器: 尽管 Symfony 5.3 仍然支持 Guard 认证器,但 Symfony 推荐使用新的 AuthenticatorInterface。对于新项目,可以考虑使用 make:authenticator 命令生成基于新接口的认证器。然而,对于现有基于 Guard 的项目,上述配置仍然有效。
  • JWT 库: Firebase\JWT\JWT 是一个常用的 PHP JWT 库。确保您的项目中已通过 Composer 安装了它。

通过遵循这些步骤和注意事项,您可以在 Symfony 5.3 应用中构建一个健壮且安全的基于 JWT 的无状态 API。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
PHP Symfony框架
PHP Symfony框架

本专题专注于PHP主流框架Symfony的学习与应用,系统讲解路由与控制器、依赖注入、ORM数据操作、模板引擎、表单与验证、安全认证及API开发等核心内容。通过企业管理系统、内容管理平台与电商后台等实战案例,帮助学员全面掌握Symfony在企业级应用开发中的实践技能。

78

2025.09.11

composer是什么插件
composer是什么插件

Composer是一个PHP的依赖管理工具,它可以帮助开发者在PHP项目中管理和安装依赖的库文件。Composer通过一个中央化的存储库来管理所有的依赖库文件,这个存储库包含了各种可用的依赖库的信息和版本信息。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

153

2023.12.25

json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

419

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

535

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

311

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

77

2025.09.10

session失效的原因
session失效的原因

session失效的原因有会话超时、会话数量限制、会话完整性检查、服务器重启、浏览器或设备问题等等。详细介绍:1、会话超时:服务器为Session设置了一个默认的超时时间,当用户在一段时间内没有与服务器交互时,Session将自动失效;2、会话数量限制:服务器为每个用户的Session数量设置了一个限制,当用户创建的Session数量超过这个限制时,最新的会覆盖最早的等等。

315

2023.10.17

session失效解决方法
session失效解决方法

session失效通常是由于 session 的生存时间过期或者服务器关闭导致的。其解决办法:1、延长session的生存时间;2、使用持久化存储;3、使用cookie;4、异步更新session;5、使用会话管理中间件。

749

2023.10.18

俄罗斯Yandex引擎入口
俄罗斯Yandex引擎入口

2026年俄罗斯Yandex搜索引擎最新入口汇总,涵盖免登录、多语言支持、无广告视频播放及本地化服务等核心功能。阅读专题下面的文章了解更多详细内容。

158

2026.01.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Sass 教程
Sass 教程

共14课时 | 0.8万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3万人学习

CSS教程
CSS教程

共754课时 | 24.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号