Symfony3.4中Entity认证提供者失效,返回401错误
我之前在Symfony 3.4搭配DoctrineMongoDBBundle做JWT登录的时候,也碰到过一模一样的问题——in_memory能正常拿令牌,换成数据库用户就报401“bad credentials”。结合当时踩的坑,给你几个排查和解决的方向:
检查User Provider配置是否适配MongoDB
很多人会犯的错是用了ORM的entityprovider,但你用的是DoctrineMongoDBBundle,得用专门的mongodbprovider配置:security: providers: app_user_provider: mongodb: class: AppBundle\Document\User # 你的User文档类完整命名空间 property: username # 登录时用的字段,比如email要确保
class指向的是MongoDB的Document类,不是ORM的Entity类,property要和你登录请求里传的用户名参数一致。确认User文档类正确实现UserInterface
Symfony的安全组件要求用户类必须实现Symfony\Component\Security\Core\User\UserInterface,并且要完整实现所有方法:getUsername():返回登录用的标识(比如用户名或邮箱)getPassword():返回加密后的密码哈希getSalt():如果用的是带盐的加密算法,返回盐值;bcrypt/argon2系列可以返回nullgetRoles():返回用户角色数组(比如['ROLE_USER'])eraseCredentials():清空敏感数据(比如临时存储的明文密码)equals():用于比较用户对象(Symfony 3.4版本需要这个方法)
另外,一定要确保密码字段存储的是加密后的哈希值,不能是明文。注册用户时必须用
UserPasswordEncoderInterface来加密密码,比如:$encodedPassword = $passwordEncoder->encodePassword($user, $plainPassword); $user->setPassword($encodedPassword);密码编码器配置要匹配
在security.yml里要明确指定用户类对应的加密算法,确保和你存储密码时用的一致:security: encoders: AppBundle\Document\User: algorithm: bcrypt # 或者argon2i、argon2id,根据你的实际使用情况如果你用了
auto模式,Symfony会自动检测,但有时候针对MongoDB文档类可能会出问题,明确指定更稳妥。登录请求参数要和Provider配置对应
如果你用的是json_login(LexikJWT常用的方式),要确保请求里的参数名和Provider的property匹配,或者在配置里指定username_path和password_path:security: firewalls: login: pattern: ^/login stateless: true json_login: check_path: /login username_path: email # 如果用邮箱登录,这里改成email password_path: password success_handler: lexik_jwt_authentication.handler.authentication_success failure_handler: lexik_jwt_authentication.handler.authentication_failure provider: app_user_provider # 这里要指向你配置的mongodb provider直接验证数据库里的用户数据
去MongoDB里查看用户文档,确认:- 用户确实存在,且登录用的字段(比如username/email)和你请求里传的一致
- 密码字段是加密后的哈希(比如bcrypt的哈希以
$2y$开头)
可以用Symfony控制台命令生成测试哈希:
php bin/console security:encode-password把生成的哈希替换到数据库里,再测试登录,如果能成功,说明之前的密码加密过程有问题。
调试用户加载流程
可以在你的User文档类的相关方法(比如getPassword)或者自定义Provider的loadUserByUsername方法里加日志输出,看Symfony是否正确加载了用户,以及返回的密码哈希是否正确。也可以用Symfony的调试工具栏查看请求过程中的用户加载情况。
内容的提问来源于stack exchange,提问作者user3868971

