Symfony7.1中LexikJWTAuthentication Authenticator不支持登录请求问题
使用Symfony 7.1 + API Platform + LexikJWTAuthentication,登录端点为http://localhost:8000/api/login。日志显示登录请求由JsonLoginAuthenticator处理,而非LexikJWTAuthenticationBundle的JWTAuthenticator。虽然Token能正常生成,但需要让JWTAuthenticator接管认证流程,以便编写JWT相关的事件订阅者。
日志内容
[2024-10-20T22:45:57.614291+00:00] request.INFO: Matched route "login". {"route":"login","route_parameters":{"_route":"login"},"request_uri":"http://localhost:8000/api/login","method":"POST"} [] [2024-10-20T22:45:57.634711+00:00] security.DEBUG: Checking for authenticator support. {"firewall_name":"main","authenticators":2} [] [2024-10-20T22:45:57.634753+00:00] security.DEBUG: Checking support on authenticator. {"firewall_name":"main","authenticator":"Lexik\Bundle\JWTAuthenticationBundle\Security\Authenticator\JWTAuthenticator"} [] [2024-10-20T22:45:57.634779+00:00] security.DEBUG: Authenticator does not support the request. {"firewall_name":"main","authenticator":"Lexik\Bundle\JWTAuthenticationBundle\Security\Authenticator\JWTAuthenticator"} [] [2024-10-20T22:45:57.634796+00:00] security.DEBUG: Checking support on authenticator. {"firewall_name":"main","authenticator":"Symfony\Component\Security\Http\Authenticator\JsonLoginAuthenticator"} []
现有配置文件
security.yml
security: password_hashers: Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto' providers: app_user_provider: entity: class: App\Entity\User property: email firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false main: stateless: true provider: app_user_provider json_login: check_path: login username_path: email password_path: password success_handler: lexik_jwt_authentication.handler.authentication_success failure_handler: lexik_jwt_authentication.handler.authentication_failure jwt: api: pattern: ^/api stateless: true jwt: ~ access_control: - { path: ^/api/login, roles: PUBLIC_ACCESS } - { path: ^/api/register, roles: PUBLIC_ACCESS } - { path: ^/api$, roles: IS_AUTHENTICATED_FULLY } when@test: security: password_hashers: Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: algorithm: auto cost: 4 # Lowest possible value for bcrypt time_cost: 3 # Lowest possible value for argon memory_cost: 10 # Lowest possible value for argon
routes.yml
controllers: resource: path: ../src/Controller/ namespace: App\Controller type: attribute login: path: /api/login methods: ['POST']
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 api_platform: check_path: /api/login username_path: email password_path: security.credentials.password
解决方案
问题根源是同时配置了Symfony原生的json_login和LexikJWT的API Platform集成,导致JsonLoginAuthenticator优先匹配并处理登录请求。要让JWTAuthenticator接管,按以下步骤调整:
移除security.yml中的json_login配置
删除main防火墙下的json_login块,这部分配置是冗余的,LexikJWT的API Platform集成已自带登录处理逻辑:# 删掉整个json_login块 json_login: check_path: login username_path: email password_path: password success_handler: lexik_jwt_authentication.handler.authentication_success failure_handler: lexik_jwt_authentication.handler.authentication_failure合并防火墙配置
由于api防火墙已经匹配所有^/api路径,建议删除多余的main防火墙,简化配置:firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false api: pattern: ^/api stateless: true provider: app_user_provider jwt: ~修正lexik_jwt_authentication.yaml的password_path配置
原配置中的password_path: security.credentials.password是错误的,应该直接对应登录请求JSON里的password字段:api_platform: check_path: /api/login username_path: email password_path: password清理缓存
配置修改后执行缓存清理:php bin/console cache:clear
完成以上操作后,登录请求会由JWTAuthenticator处理,你可以正常编写JWT认证相关的事件订阅者。
内容的提问来源于stack exchange,提问作者CitizenG1

