Symfony 6.2登录表单未调用自定义哈希类的问题排查
Symfony自定义密码哈希器登录不生效(命令行正常)
问题概述
在PHP 8.1 + Symfony 6.2项目中,已配置自定义密码哈希类CustomVerySecureHasher并绑定到App\Entity\Useraccount实体:
- 执行命令
php bin/console security:hash-password testPpassword时,自定义哈希类可正常生成MD5哈希 - 通过GUI登录表单验证时,密码验证流程从未进入自定义哈希类,导致输入密码与数据库哈希值不匹配,无法登录
- 执行
php bin/console debug:config security发现,App\Entity\Useraccount的哈希配置显示hash_algorithm: sha512,与配置的自定义类不符
相关配置与代码
security.yaml
security: password_hashers: App\Entity\Useraccount: id: 'App\Security\Hasher\CustomVerySecureHasher' providers: users_in_memory: { memory: null } firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false main: lazy: true provider: users_in_memory custom_authenticator: App\Security\AppCustomAuthenticator access_control: 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
CustomVerySecureHasher类
<?php namespace App\Security\Hasher; use Exception; use Symfony\Component\PasswordHasher\PasswordHasherInterface; class CustomVerySecureHasher implements PasswordHasherInterface { public function hash(string $plainPassword): string { if (!in_array('md5', hash_algos(), true)) { throw new Exception('MD5 is not supported by this system.'); } return md5($plainPassword); } public function verify(string $hashedPassword, string $plainPassword): bool { return $hashedPassword === md5($plainPassword); } public function needsRehash(string $hashedPassword): bool { return false; } }
AppCustomAuthenticator类
<?php namespace App\Security; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Security; use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials; use Symfony\Component\Security\Http\Authenticator\Passport\Passport; use Symfony\Component\Security\Http\Util\TargetPathTrait; class AppCustomAuthenticator extends AbstractLoginFormAuthenticator { use TargetPathTrait; public const LOGIN_ROUTE = 'app_login'; public function __construct(private UrlGeneratorInterface $urlGenerator) { } public function authenticate(Request $request): Passport { $login = $request->request->get('login', ''); $request->getSession()->set(Security::LAST_USERNAME, $login); return new Passport( new UserBadge($login), new PasswordCredentials($request->request->get('password', '')), [ new CsrfTokenBadge('authenticate', $request->request->get('_csrf_token')), ] ); } public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response { if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) { return new RedirectResponse($targetPath); } return new RedirectResponse($this->urlGenerator->generate('app_home')); } protected function getLoginUrl(Request $request): string { return $this->urlGenerator->generate(self::LOGIN_ROUTE); } }
问题原因
核心问题是登录使用的用户提供者是内存提供者users_in_memory,而非绑定自定义哈希器的Useraccount实体提供者:
- 自定义哈希器的配置是绑定到
App\Entity\Useraccount实体的,只有当Symfony加载该实体类的用户时,才会使用对应的自定义哈希器 - 当前防火墙使用
users_in_memory提供者,Symfony会对内存用户使用默认的哈希配置(或继承自PasswordAuthenticatedUserInterface的全局配置),因此不会触发自定义哈希类 debug:config显示的hash_algorithm: sha512是Symfony为内存用户 fallback 的默认哈希算法,与你配置的自定义类无关
解决方案
1. 替换用户提供者为实体提供者
修改security.yaml的providers和firewalls.main部分,让Symfony从数据库加载Useraccount实体:
security: # ... 其他配置 providers: # 替换原有的users_in_memory app_user_provider: entity: class: App\Entity\Useraccount property: login # 替换为你的Useraccount实体中用于登录的字段(如username/email) firewalls: main: lazy: true provider: app_user_provider # 使用新的实体提供者 custom_authenticator: App\Security\AppCustomAuthenticator # ... 其他配置
2. 确保Useraccount实体实现必要接口
Useraccount实体必须实现UserInterface和PasswordAuthenticatedUserInterface,并正确实现相关方法:
<?php namespace App\Entity; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\UserInterface; #[ORM\Entity(repositoryClass: UseraccountRepository::class)] class Useraccount implements UserInterface, PasswordAuthenticatedUserInterface { #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column(type: 'integer')] private ?int $id = null; #[ORM\Column(type: 'string', length: 180, unique: true)] private ?string $login = null; #[ORM\Column(type: 'string')] private ?string $password = null; // ... 其他字段、getter和setter public function getUserIdentifier(): string { return (string) $this->login; } public function getRoles(): array { // 返回用户角色,例如 ['ROLE_USER'] return ['ROLE_USER']; } public function getPassword(): ?string { return $this->password; } public function eraseCredentials(): void { // 可选:清除敏感数据,如明文密码(如果有存储) } }
3. 清理缓存
执行命令清除缓存,确保配置生效:
php bin/console cache:clear
验证
- 重新测试登录流程,此时密码验证会调用
CustomVerySecureHasher::verify()方法 - 再次执行
php bin/console debug:config security,确认App\Entity\Useraccount的哈希配置已正确使用自定义类的ID
内容的提问来源于stack exchange,提问作者Spinogl
相关产品推荐
相关产品推荐

