Symfony 6.2配置MD5密码哈希验证失败,寻求解决方案
问题描述
我正在将一个重型Java应用迁移至Symfony 6.2开发的Web应用,要求完全沿用现有数据库,该数据库中密码采用MD5哈希存储。我已能通过hash('md5', $password)实现MD5哈希,但希望像Symfony默认方式一样自动完成哈希验证。
我按照Symfony文档尝试在security.yaml中添加如下配置:
password_hashers: app_hasher: id: 'App\Security\Hasher\CustomVerySecureHasher'
并创建了对应的CustomVerySecureHasher类:
class CustomVerySecureHasher implements PasswordHasherInterface { public function hash(string $plainPassword): string { // Check if the MD5 hash algorithm is supported if (!in_array('md5', hash_algos(), true)) { throw new Exception('MD5 is not supported by this system.'); } // Hash the password using the MD5 algorithm return md5($plainPassword); } public function verify(string $hashedPassword, string $plainPassword): bool { // Compare the hashed password with the MD5 hashed plaintext password return $hashedPassword === md5($plainPassword); } public function needsRehash(string $hashedPassword): bool { // There is no need to rehash with MD5, as it is considered insecure return false; } }
但该配置并未生效。我已确认通过表单能正确获取登录账号和密码,问题出在哈希验证环节。以下是我的相关代码及配置:
AppCustomAuthenticator类
class AppCustomAuthenticator extends AbstractLoginFormAuthenticator { use TargetPathTrait; public const LOGIN_ROUTE = 'app_login'; public function __construct(private UrlGeneratorInterface $urlGenerator) { } public function authenticate(Request $request): Passport { $email = $request->request->get('login', ''); $request->getSession()->set(Security::LAST_USERNAME, $email); // $password = $request->request->get('password', ''); // $test = hash('md5', $password); // dd($test); return new Passport( new UserBadge($email), 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); } // For example: // return new RedirectResponse($this->urlGenerator->generate('some_route')); throw new \Exception('TODO: provide a valid redirect inside '.__FILE__); } protected function getLoginUrl(Request $request): string { return $this->urlGenerator->generate(self::LOGIN_ROUTE); } }
登录控制器代码
#[Route(path: '/', name: 'app_login')] public function login(AuthenticationUtils $authenticationUtils): Response { // if ($this->getUser()) { // return $this->redirectToRoute('target_path'); // } // get the login error if there is one $error = $authenticationUtils->getLastAuthenticationError(); // last username entered by the user $lastUsername = $authenticationUtils->getLastUsername(); // if ($lastUsername) { // dd($lastUsername); // } return $this->render('/security/login.html.twig', ['login' => $lastUsername, 'error' => $error]); }
完整的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
使用环境:PHP 8.1、Symfony 6.2
解决思路
1. 替换用户提供者配置
当前使用的users_in_memory内存提供者不会从数据库加载用户,无法匹配数据库中的MD5密码。需要替换为数据库实体提供者:
修改security.yaml的providers和main防火墙配置:
providers: app_user_provider: entity: class: App\Entity\Useraccount property: email # 替换为Useraccount实体中存储登录账号的字段(如username,需和表单提交的login参数对应) firewalls: main: lazy: true provider: app_user_provider # 替换原有的users_in_memory custom_authenticator: App\Security\AppCustomAuthenticator
2. 完善User实体接口实现
App\Entity\Useraccount必须实现PasswordAuthenticatedUserInterface和UserInterface,并实现必要方法:
namespace App\Entity; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\UserInterface; class Useraccount implements UserInterface, PasswordAuthenticatedUserInterface { // 实体原有字段和方法 public function getPassword(): string { return $this->password; // 返回数据库中存储MD5哈希的字段 } public function getRoles(): array { // 根据业务逻辑返回角色,默认可返回['ROLE_USER'] return ['ROLE_USER']; } public function eraseCredentials() { // 无需处理,留空即可 } public function getUserIdentifier(): string { return $this->email; // 和提供者配置的property字段一致,返回用户唯一标识 } }
3. 确保自定义哈希器被容器识别
如果Symfony未自动注册CustomVerySecureHasher,需在services.yaml中手动配置:
services: App\Security\Hasher\CustomVerySecureHasher: autowire: true autoconfigure: true
4. 验证配置并清除缓存
完成所有修改后,清除Symfony缓存:
php bin/console cache:clear
此时登录流程会自动调用自定义哈希器的verify方法,对比提交密码的MD5哈希与数据库存储值。
内容的提问来源于stack exchange,提问作者Spinogl
相关产品推荐
相关产品推荐

