php - 密码没有得到散列,并尝试连接返回错误 500 Symfony
问题描述
总的来说,我对 Symfony 还是很陌生,我主要使用它是因为我需要非常快速地做一些安全的事情,并且还需要发现 Symfony 4。
我正在尝试与安全配方建立安全连接,但我面临两个主要问题(可能相关)和一个小问题。
首先,我尝试将 salt 定义为可为空,但它仍在NOT NULL
db 中。这是我对列的定义:
/**
* @ORM\Column(name="salt", type="string", nullable=true)
*/
private $salt;
所以现在的大问题:我添加的密码没有散列并且尝试连接返回错误 500
我试图遵循文档,这里是:我的实体
use Doctrine\ORM\Mapping as ORM;
use PhpParser\Node\Scalar\String_;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* @ORM\Table(name="app_user")
* @ORM\Entity(repositoryClass="App\Repository\UserRepository")
*/
class User implements UserInterface, \Serializable
{
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\Column(type="string", length=25, unique=true)
*/
private $username;
/**
* @ORM\Column(type="string", length=255)
*/
private $password;
/**
* @ORM\Column(type="string", length=254, unique=true, nullable=true)
*/
private $email;
/**
* @ORM\Column(name="is_active", type="boolean")
*/
private $isActive;
/**
* @ORM\Column(name="salt", type="string", nullable=true)
*/
private $salt;
/**
* @ORM\Column(name="alias", type="string")
*/
private $alias;
/**
* @return mixed
*/
public function getAlias()
{
return $this->alias;
}
/**
* @param mixed $alias
*/
public function setAlias($alias): void
{
$this->alias = $alias;
}
public function __construct()
{
$this->isActive = true;
// may not be needed, see section on salt below
// $this->salt = md5(uniqid('', true));
}
public function getUsername()
{
return $this->username;
}
public function getSalt() :String
{
// you *may* need a real salt depending on your encoder
// see section on salt below
return $this->salt;
}
public function getPassword()
{
return $this->password;
}
public function getRoles()
{
return array('ROLE_USER');
}
public function eraseCredentials()
{
}
/** @see \Serializable::serialize() */
public function serialize()
{
return serialize([
$this->id,
$this->username,
$this->password,
// see section on salt below
// $this->salt
]);
}
/** @see \Serializable::unserialize() */
public function unserialize($serialized)
{
list (
$this->id,
$this->username,
$this->password,
// see section on salt below
// $this->salt
) = unserialize($serialized, ['allowed_classes' => false]);
}
/**
* @return mixed
*/
public function getId()
{
return $this->id;
}
/**
* @param mixed $id
*/
public function setId($id): void
{
$this->id = $id;
}
/**
* @return mixed
*/
public function getEmail()
{
return $this->email;
}
/**
* @param mixed $email
*/
public function setEmail($email): void
{
$this->email = $email;
}
/**
* @return mixed
*/
public function getisActive()
{
return $this->isActive;
}
/**
* @param mixed $isActive
*/
public function setIsActive($isActive): void
{
$this->isActive = $isActive;
}
/**
* @param mixed $username
*/
public function setUsername($username): void
{
$this->username = $username;
}
/**
* @param mixed $password
*/
public function setPassword($password): void
{
$this->password = $password;
}
/**
* @param mixed $salt
*/
public function setSalt($salt): void
{
$this->salt = $salt;
}
}
我的控制器
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
class SecurityController extends Controller
{
/**
* @Route("/login", name="login")
*/
public function login(Request $request, AuthenticationUtils $authenticationUtils)
{
// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('security/login.html.twig', array(
'last_username' => $lastUsername,
'error' => $error,
));
}
}
和
use App\Entity\User;
use App\Form\UserType;
use App\Repository\UserRepository;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
/**
* @Route("/user")
*/
class UserController extends Controller
{
/**
* @Route("/", name="user_index", methods="GET")
*/
public function index(UserRepository $userRepository): Response
{
return $this->render('user/index.html.twig', ['users' => $userRepository->findAll()]);
}
/**
* @Route("/new", name="user_new", methods="GET|POST")
*/
public function new(Request $request): Response
{
$user = new User();
$form = $this->createForm(UserType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
return $this->redirectToRoute('user_index');
}
return $this->render('user/new.html.twig', [
'user' => $user,
'form' => $form->createView(),
]);
}
/**
* @Route("/{id}", name="user_show", methods="GET")
*/
public function show(User $user): Response
{
return $this->render('user/show.html.twig', ['user' => $user]);
}
/**
* @Route("/{id}/edit", name="user_edit", methods="GET|POST")
*/
public function edit(Request $request, User $user): Response
{
$form = $this->createForm(UserType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('user_edit', ['id' => $user->getId()]);
}
return $this->render('user/edit.html.twig', [
'user' => $user,
'form' => $form->createView(),
]);
}
/**
* @Route("/{id}", name="user_delete", methods="DELETE")
*/
public function delete(Request $request, User $user): Response
{
if ($this->isCsrfTokenValid('delete'.$user->getId(), $request->request->get('_token'))) {
$em = $this->getDoctrine()->getManager();
$em->remove($user);
$em->flush();
}
return $this->redirectToRoute('user_index');
}
public function register(User $user, UserPasswordEncoderInterface $encoder)
{
$plainPassword = $user->getPassword();
$encoded = $encoder->encodePassword($user, $plainPassword);
$user->setPassword($encoded);
}
}
和我的 security.yaml
security:
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
db_provider:
entity:
class: App\Entity\User
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: ~
provider: db_provider
form_login:
login_path: login
check_path: login
logout:
path: /logout
target: /homepage
pattern: ^/admin
http_basic: ~
encoders:
App\Entity\User:
algorithm: argon2i
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
在我的 UserController::new() 检查 isSubmited 和 isValid 后,我尝试添加它
$plainPassword = $user->getPassword;
$encoded = $encoder->encodePassword($user, $plainPassword);
$user->setPassword($encoded);
但是我有一个错误说UserPasswordEncoderInterface $encoder
加载表单时没有注入我作为方法传递的参数。我仍然不确定让它工作是否是一个好的解决方案,因为我必须在 UserController::edit() 中复制该逻辑,这看起来不像 Symfony 的代码。
(错误 :)
"Controller "App\Controller\UserController::new()" 要求您为 "$encoder" 参数提供一个值。参数可以为空且未提供空值,未提供默认值,或者因为存在在此之后是一个非可选参数。”
我还尝试复制/粘贴(我多么绝望……)我的 UserController 和 SecurityController 中的代码,但这也不起作用
public function register(UserPasswordEncoderInterface $encoder)
{
// whatever *your* User object is
$user = new App\Entity\User();
$plainPassword = 'ryanpass';
$encoded = $encoder->encodePassword($user, $plainPassword);
$user->setPassword($encoded);
}
我从服务器得到这个作为日志:
“没有为帐户“App\Entity\User”配置编码器。”
我还尝试直接在我的数据库中插入一些值,但是在输入正确的密码时尝试连接给了我“拒绝访问”消息,我认为这是另一个问题......
我真的不明白我哪里错了,我找不到人问这个问题。如果您能帮助我,我将不胜感激。
注意:UserController 路由以 /user 开头并且是完全公开的,因为我需要一个用户来访问安全的管理面板。
编辑我正在使用 MySQL 5.7 和 PHP 7.2,如果可以的话
解决方案
由于您使用 Argon2i 作为实体的编码器算法,因此您$salt
已过时:
您需要使用 Salt 属性吗?
如果您使用 bcrypt 或 argon2i,则不会。否则,是的。所有密码都必须使用盐进行哈希处理,但 bcrypt 和 argon2i 在内部执行此操作 [...] User 中的 getSalt() 方法只能返回 null (未使用)。[...]
尝试删除$salt
属性和 setter 方法,然后让您的getSalt()
return null
. 持久化用户而不进行编码操作并检查持久化密码。
虽然这可以被视为一种肮脏的黑客行为,但这似乎是一种很好的做法......
推荐阅读
- node.js - Node.js 模块 CSURF 问题——如何计算 ANTI-CSRF 令牌?
- python - 关于 mpi4py Scatter large arrays 的问题
- solidity - 在调用“removeLiquidity”pancakeSwap 后发现“ds-math-sub-underflow”恢复
- python - Python Pong 碰撞不合作
- java - 如何使用字符串作为条件进行切换案例场景?
- android - OnResume 正在触发而不是 OnStart 和 onCreate
- neovim - 如何在 SpaceVim 中使用 netrw?
- c++ - MSVC 是双重编码 UTF-8 字符串,为什么?
- c++ - 带有自定义分配器的 unique_ptr
- javascript - 通过io.sockets.sockets解析时如何获取socket id