Symfony 6.4中SuperUser登录跳转后丢失用户问题排查
Symfony 6.4 SuperUser登录后状态丢失问题
在Symfony 6.4应用中为新实体SuperUser实现登录功能,严格遵循官方文档操作,登录验证成功,但跳转至其他页面或访问新页面后,登录用户状态丢失。
已排查方向:
- 测试会话可正常存储数据,调整会话配置无效;
- 尝试自定义Authenticator未解决问题;
- 日志和调试工具无有效报错提示;
- 已简化
security.yaml配置,怀疑FOSUserBundle或FOSOAuthServerBundle存在干扰,但未定位具体原因。
日志信息
[2024-09-16T17:27:20.694109+02:00] security.INFO: Authenticator successful! {"token":{"Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken":"UsernamePasswordToken(user=\"tomatom\", roles=\"ROLE_SUPER_ADMIN, ROLE_USER\")"},"authenticator":"Symfony\Component\Security\Http\Authenticator\FormLoginAuthenticator"} [] [2024-09-16T17:27:20.696821+02:00] app.DEBUG: Notified event "security.interactive_login" to listener "FOS\UserBundle\EventListener\LastLoginListener::onSecurityInteractiveLogin". {"event":"security.interactive_login","listener":"FOS\UserBundle\EventListener\LastLoginListener::onSecurityInteractiveLogin"} [] [2024-09-16T17:27:20.926611+02:00] app.DEBUG: Notified event "Symfony\Component\Security\Http\Event\LoginSuccessEvent" to listener "Symfony\Component\Security\Http\EventListener\SessionStrategyListener::onSuccessfulLogin". {"event":"Symfony\Component\Security\Http\Event\LoginSuccessEvent","listener":"Symfony\Component\Security\Http\EventListener\SessionStrategyListener::onSuccessfulLogin"} [] [2024-09-16T17:27:20.926800+02:00] app.DEBUG: Notified event "Symfony\Component\Security\Http\Event\LoginSuccessEvent" to listener "Symfony\Component\Security\Http\EventListener\PasswordMigratingListener::onLoginSuccess". {"event":"Symfony\Component\Security\Http\Event\LoginSuccessEvent","listener":"Symfony\Component\Security\Http\EventListener\PasswordMigratingListener::onLoginSuccess"} [] [2024-09-16T17:27:20.926905+02:00] security.DEBUG: The "Symfony\Component\Security\Http\Authenticator\FormLoginAuthenticator" authenticator set the response. Any later authenticator will not be called {"authenticator":"Symfony\Component\Security\Http\Authenticator\FormLoginAuthenticator"} [] [2024-09-16T17:27:21.044256+02:00] doctrine.INFO: Disconnecting [] [] [2024-09-16T17:27:21.146985+02:00] request.INFO: Matched route "admin_company_list". {"route":"admin_company_list","route_parameters":{"_route":"admin_company_list","_controller":"App\Controller\CompanyController::index"},"request_uri":"http://127.0.0.5/admin/company/list","method":"GET"} [] [2024-09-16T17:27:21.364243+02:00] security.DEBUG: Checking for authenticator support. {"firewall_name":"admin","authenticators":1} [] [2024-09-16T17:27:21.364393+02:00] security.DEBUG: Checking support on authenticator. {"firewall_name":"admin","authenticator":"Symfony\Component\Security\Http\Authenticator\FormLoginAuthenticator"} [] [2024-09-16T17:27:21.364464+02:00] security.DEBUG: Authenticator does not support the request. {"firewall_name":"admin","authenticator":"Symfony\Component\Security\Http\Authenticator\FormLoginAuthenticator"} [] [2024-09-16T17:27:21.416471+02:00] security.DEBUG: Access denied, the user is not fully authenticated; redirecting to authentication entry point. {"exception":"[object] (Symfony\Component\Security\Core\Exception\AccessDeniedException(code: 403): Access Denied. at /var/www/vendor/symfony/security-http/Firewall/AccessListener.php:87)"} []
简化后的security.yaml配置
security: password_hashers: App\Entity\SuperUser: 'auto' providers: super_user_provider: entity: class: App\Entity\SuperUser property: username firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false admin: pattern: ^/admin provider: super_user_provider stateless: false form_login: login_path: admin_login check_path: admin_login enable_csrf: false default_target_path: admin_company_list logout: path: admin_logout role_hierarchy: ROLE_SUPER_ADMIN: ~ ROLE_ORDER_SELLITEMS: ~ ROLE_SALESMAN: ~ ROLE_SERVER_ADMIN: - ROLE_ORDER_SHOW ROLE_PICKING_REQUIRED_NOTE: ~ ROLE_ORDER_GROUP_ONLY_MY: ~ ROLE_CUSTOMER_ONLY_MY: ~ access_control: - { path: '^/admin/login/[a-z]{2}', roles: [ PUBLIC_ACCESS ] } - { path: ^/admin, roles: [ ROLE_SERVER_ADMIN, IS_AUTHENTICATED_FULLY ] }
FOS相关配置
fos_oauth_server.yaml
fos_oauth_server: db_driver: orm client_class: App\Entity\OAuth\Client access_token_class: App\Entity\OAuth\AccessToken refresh_token_class: App\Entity\OAuth\RefreshToken auth_code_class: App\Entity\OAuth\AuthCode service: user_provider: fos_user.user_provider.username_email options: supported_scopes: user access_token_lifetime: 43200 refresh_token_lifetime: 1209600 services: fos_oauth_server.client_manager: class: App\Util\ClientManager arguments: - '@App\Repository\ClientRepository'
fos_user.yaml
fos_user: from_email: address: '%env(resolve:SENDER_EMAIL_ADDRESS)%' sender_name: '%env(resolve:SENDER_EMAIL_NAME)%' db_driver: orm firewall_name: fos_user user_class: App\Entity\User service: mailer: App\Service\FosMailer
NelmioCorsBundle配置
nelmio_cors: defaults: allow_credentials: false allow_origin: [] allow_headers: [] allow_methods: [] expose_headers: [] max_age: 0 hosts: [] origin_regex: false paths: '^/': origin_regex: true allow_origin: ['^http://localhost:[0-9]+'] allow_headers: ['*'] allow_methods: ['POST', 'PUT', 'GET', 'DELETE'] max_age: 3600 hosts: ['^api\.']
相关业务代码
SuperUser.php
#[ORM\Table(name: 'super_user')] #[ORM\Entity(repositoryClass: SuperUserRepository::class)] #[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_USERNAME', fields: ['username'])] class SuperUser implements UserInterface, PasswordAuthenticatedUserInterface { ... }
LoginController.php
#[Route('/admin/login/{_locale}', name: 'admin_login')] public function login(AuthenticationUtils $authenticationUtils): Response { $error = $authenticationUtils->getLastAuthenticationError(); $lastUsername = $authenticationUtils->getLastUsername(); return $this->render('login/index.html.twig', [ 'last_username' => $lastUsername, 'error' => $error, ]); }
登录表单
<form action="{{ path('admin_login') }}" method="post"> <input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}"> <label for="username">Jméno:</label> <input type="text" id="username" name="_username" class="form-control my-1" value="{{ last_username }}" required> <label for="password">Heslo:</label> <input type="password" id="password" name="_password" class="form-control my-1" required> <input type="hidden" name="_target_path" value="{{ path('admin_company_list') }}"> <button type="submit" class="btn btn-primary float-end my-2">Přihlásit</button> </form>
内容的提问来源于stack exchange,提问作者Matys333
相关产品推荐
相关产品推荐

