解决 Symfony 中的 JWT 签名问题:配置故障排除

解决 Symfony 中的 JWT 签名问题:配置故障排除
解决 Symfony 中的 JWT 签名问题:配置故障排除

Symfony 中 JWT 签名问题故障排除简介

使用 Symfony 和 JSON Web 令牌 (JWT) 时,您可能会遇到与从给定配置创建签名 JWT 相关的问题。遵循文档至关重要,但即使严格遵守,也可能会出现问题。

本文解决了 Symfony 中 JWT 配置期间遇到的常见问题,特别关注错误消息“无法从给定配置创建签名的 JWT”。我们将探讨一个实际示例并提供故障排除步骤来帮助您解决这些问题。

命令 描述
openssl genrsa -out config/jwt/private.pem -aes256 4096 生成采用 AES-256 加密且密钥长度为 4096 位的新 RSA 私钥。
openssl rsa -pubout -in config/jwt/private.pem -out config/jwt/public.pem 从生成的 RSA 私钥中提取公钥。
token_ttl: 3600 将 JWT 令牌的生存时间设置为 3600 秒(1 小时)。
pass_phrase: '%env(JWT_PASSPHRASE)%' 指定用于私钥的密码,从环境变量中检索。
json_login: check_path: /api/login_check 配置基于 JSON 的身份验证的登录端点。
firewalls: api: stateless: true 指示 API 防火墙不应管理会话,使其成为无状态的。

了解配置和脚本

提供的第一个脚本将 Symfony 配置为使用 JWT 身份验证。配置在 YAML 文件中定义,特别是在 lexik_jwt_authentication.yamlsecurity.yaml 文件。在 lexik_jwt_authentication.yaml, 这 secret_keypublic_key 参数指向 RSA 密钥的路径,而 pass_phrase 用于保护私钥。这 token_ttl 将令牌的生存时间设置为 3600 秒,确保令牌在一小时后过期。此配置可确保用于在 Symfony 应用程序中验证 API 请求的 JWT 的安全性和完整性。

第二个脚本涉及使用 OpenSSL 生成 RSA 密钥。命令 openssl genrsa -out config/jwt/private.pem -aes256 4096 创建采用 AES-256 加密且密钥大小为 4096 位的私钥。随后的命令, openssl rsa -pubout -in config/jwt/private.pem -out config/jwt/public.pem,提取对应的公钥。这些密钥对于签名和验证 JWT 至关重要,为保护 API 通信提供了可靠的方法。在提供的 security.yaml,防火墙配置为处理登录和 API 路由。这 json_login setup 指定用户身份验证的端点,利用成功和失败登录尝试的处理程序。

配置 Symfony 进行 JWT 身份验证

使用 YAML 配置 Symfony

# 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

# config/packages/security.yaml
security:
    encoders:
        App\Entity\User:
            algorithm: auto

    providers:
        app_user_provider:
            entity:
                class: App\Entity\User
                property: email

    firewalls:
        login:
            pattern:  ^/api/login
            stateless: true
            json_login:
                check_path: /api/login_check
                success_handler: lexik_jwt_authentication.handler.authentication_success
                failure_handler: lexik_jwt_authentication.handler.authentication_failure
                username_path: email
                password_path: password

        api:
            pattern:   ^/api
            stateless: true
            provider: app_user_provider
            jwt: ~

    access_control:
        - { path: ^/api/login, roles: PUBLIC_ACCESS }
        - { path: ^/api,       roles: IS_AUTHENTICATED_FULLY }

为 Symfony 生成 JWT 密钥

OpenSSL 的命令行脚本

openssl genrsa -out config/jwt/private.pem -aes256 4096
openssl rsa -pubout -in config/jwt/private.pem -out config/jwt/public.pem

JWT 的 Symfony 实体配置

用户实体的 PHP 脚本

<?php
namespace App\Entity;

use App\Repository\UserRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;

#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_EMAIL', fields: ['email'])]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 180)]
    private ?string $email = null;

    #[ORM\Column]
    private array $roles = [];

    #[ORM\Column]
    private ?string $password = null;

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getEmail(): ?string
    {
        return $this->email;
    }

    public function setEmail(string $email): static
    {
        $this->email = $email;
        return $this;
    }

    public function getUserIdentifier(): string
    {
        return (string) $this->email;
    }

    public function getRoles(): array
    {
        $roles = $this->roles;
        $roles[] = 'ROLE_USER';
        return array_unique($roles);
    }

    public function setRoles(array $roles): static
    {
        $this->roles = $roles;
        return $this;
    }

    public function getPassword(): string
    {
        return $this->password;
    }

    public function setPassword(string $password): static
    {
        $this->password = $password;
        return $this;
    }

    public function eraseCredentials(): void
    {
        // Clear temporary, sensitive data
    }
}

Symfony 中 JWT 配置的高级故障排除

除了基本配置和密钥生成过程之外,对 Symfony 中的 JWT 问题进行故障排除还包括确保所有环境变量均正确设置。这 JWT_SECRET_KEY, JWT_PUBLIC_KEY, 和 JWT_PASSPHRASE 必须与生成过程中使用的密钥和密码相匹配。检查密钥文件的权限也很重要,因为不正确的权限可能会阻止 Symfony 访问它们。

另一个重要方面是验证 lexik/jwt-authentication-bundle 已正确安装和配置。确保该捆绑包已在中注册 bundles.php 并且配置文件已正确加载。配置错误 security.yaml 也可能导致问题。确保防火墙和访问控制设置符合 API 的身份验证要求。使用不同的用户和角色测试设置可以帮助识别身份验证流程中的特定问题。

有关 Symfony 中 JWT 配置的常见问题

  1. 如何生成 JWT 的 RSA 密钥?
  2. 使用命令 openssl genrsa -out config/jwt/private.pem -aes256 4096 生成私钥并 openssl rsa -pubout -in config/jwt/private.pem -out config/jwt/public.pem 提取公钥。
  3. 如果出现权限错误怎么办?
  4. 确保密钥文件具有正确的权限。使用命令 19 号 设置适当的权限。
  5. 尽管遵循了文档,为什么我的 JWT 配置不起作用?
  6. 仔细检查您的环境变量 .env 文件并确保它们与密钥生成过程中使用的密钥和密码匹配。
  7. 如何测试我的 JWT 配置是否正确?
  8. 运行命令 php bin/console lexik:jwt:generate-token test@test.com 生成令牌并验证其创建是否没有错误。
  9. 有何作用 pass_phrase 在 JWT 配置中玩?
  10. pass_phrase 用于加密私钥。必须在环境变量中正确设置它,Symfony 才能在令牌创建期间使用它。
  11. 如何配置 JSON 登录路径?
  12. 在里面 security.yaml,设置 check_path 通常到您的登录端点 /api/login_check
  13. 什么是 token_ttl 参数做什么?
  14. token_ttl 参数设置 JWT 的生存时间,确定令牌保持有效的时间。
  15. 为什么我需要密钥和公钥?
  16. 密钥用于对 JWT 进行签名,而公钥用于验证令牌的签名。
  17. 我怎样才能确保 lexik/jwt-authentication-bundle 是否正确安装?
  18. 检查你的 bundles.php 文件以确保捆绑包已注册并且所有配置文件已正确加载。
  19. 防火墙在 JWT 身份验证中的作用是什么?
  20. 防火墙位于 security.yaml 定义应用程序的不同部分如何处理身份验证和授权,确保只有经过身份验证的用户才能访问某些端点。

关于解决 Symfony 中 JWT 问题的最终想法

解决 Symfony 中的错误“无法从给定配置创建签名的 JWT”需要仔细注意配置细节和依赖项。确保正确设置 OpenSSL 并准确生成和配置 RSA 密钥至关重要。仔细检查 Symfony 配置文件中的安全设置和环境变量可以帮助解决此问题。遵循本文概述的步骤将有助于在您的 Symfony 应用程序中成功实现 JWT 身份验证。