Symfony5新认证系统自定义哈希器报createHasher()参数类型错误
问题根因
- 接口实现类型错误
Symfony 安全组件的password_hashers配置项中指定的自定义哈希器服务,必须实现Symfony\Component\PasswordHasher\PasswordHasherInterface接口,你当前实现的UserPasswordHasherInterface属于上层业务工具接口,不是给底层哈希工厂消费的。哈希工厂读取配置时,没有识别到你传入的是合法的哈希器实例,误将其当做配置数组处理,所以抛出了参数必须为数组,实际为对象的错误。 - 方法逻辑与配置缺陷
- 你写的
ShaOneEncoder中isPasswordValid方法直接使用了未定义的$salt、$encoded变量,运行时会抛出变量未定义错误。 needsRehash方法返回true,会导致Symfony每次登录都尝试重写用户密码,如果你没有实现重哈希后的密码落库逻辑,就会出现登录成功后会话状态异常,触发无限重定向,这也是你用auto算法时出现死循环的核心原因。
修复方案
1. 调整自定义哈希器实现
将ShaOneEncoder改为实现PasswordHasherInterface,适配安全组件的调用规则:
<?php namespace App\Security; use Symfony\Component\PasswordHasher\PasswordHasherInterface; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; class ShaOneEncoder implements PasswordHasherInterface { private $params; public function __construct(ParameterBagInterface $params) { $this->params = $params; } /** * 生成哈希(命令行哈希密码、手动创建用户时调用,需要salt上下文时可自行扩展) */ public function hash(string $plainPassword): string { throw new \RuntimeException('生成哈希需传入用户salt,可调用encodePassword方法手动传入salt'); } /** * 校验密码(登录时安全组件自动调用,会自动传入用户的salt字段) */ public function verify(string $hashedPassword, string $plainPassword, string $salt = null): bool { if (null === $salt) { throw new \InvalidArgumentException('当前哈希器必须依赖用户salt校验密码'); } $separator = $this->params->get('standard.passwd_separator'); return sha1($plainPassword . $separator . $salt) === $hashedPassword; } /** * 判断是否需要重哈希,遗留系统直接返回false即可 */ public function needsRehash(string $hashedPassword): bool { return false; } /** * 手动生成哈希的工具方法,用于创建用户等场景 */ public function encodePassword(string $rawPassword, string $salt): string { $separator = $this->params->get('standard.passwd_separator'); return sha1($rawPassword . $separator . $salt); } }
2. 修正LoginFormAuthenticator的响应逻辑
检查onAuthenticationSuccess方法,必须返回跳转响应,避免登录成功后无响应导致的跳转异常:
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response { // 跳转到登录前的页面或者首页 return new RedirectResponse($this->urlGenerator->generate('home')); }
3. 保持security.yaml配置不变
你当前的哈希器配置已经符合要求,不需要调整。
补充说明
你观察到的接口行为差异是正常设计:
PasswordHasherInterface是底层哈希器的标准接口,安全组件的校验、哈希逻辑都会直接调用该接口的方法。UserPasswordHasherInterface是封装后的业务工具类接口,仅用于业务代码中手动调用哈希/校验逻辑,不会被安全组件的哈希工厂识别。
内容的提问来源于stack exchange,提问作者akio
相关产品推荐
相关产品推荐

