[英]Symfony / Api-platform password update on PUT even if not specified
Symfony / Api-platform updates rehash password on put request 再次登錄時出錯
我和這個人有完全相同的問題,看起來他找到了解決方案,因為他在評論中說“我的錯,我沒有完全遵循文檔。這不再是問題了”。
<?php
namespace App\Entity;
use ApiPlatform\Core\Action\NotFoundAction;
use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Repository\UserRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Validator\Constraints as Assert;
use App\Controller\MeController;
use App\Controller\ForgottenPasswordController;
use App\Controller\UpdateUser;
#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\Table(name: '`user`')]
/**
* Un utilisateur
*
* @UniqueEntity(fields={"email"}, message="Il y a déjà un compte avec cet email")
*/
#[ApiResource(
collectionOperations: [
"get" => [
"security" => "is_granted('ROLE_ADMIN')",
"security_message" => "Vous n'avez pas accès à cette ressource."
],
"post",
"me" => [
"path" => "/me",
"method" => "get",
"controller" => MeController::class,
],
"forgotten_password" => [
"method" => "post",
"path" => "/forgotten-password",
"controller" => ForgottenPasswordController::class,
"denormalization_context" => ["groups" => ["forgotten-password"]]
],
],
itemOperations: [
"get" => [
"security" => "is_granted('ROLE_ADMIN')",
"security_message" => "Vous n'avez pas accès à cette ressource."
],
// "put" => [
// "security" => "object == user or is_granted('ROLE_ADMIN')",
// "security_message" => "Vous n'avez pas accès à cette ressource."
// ],
"update_user" => [
"method" => "PUT",
"path" => "/users/{id}/update",
"controller" => UpdateUser::class,
"normalization_context"=>["groups"=>["user_update"]]
],
"delete" => [
"security" => "object == user or is_granted('ROLE_ADMIN')",
"security_message" => "Vous n'avez pas accès à cette ressource."
],
// "patch" => [
// "security" => "is_granted('ROLE_ADMIN')",
// "security_message" => "Vous n'avez pas accès à cette ressource."
// ],
// "update_password" => [
// "method" => "PUT",
// "path" => "users/{id}/update-password",
//// "controller"=> App\Controller\UserChangePassword::class,
//// "normalization_context"=>{"groups"={"user:passwordUpdate"}}
// ]
],
denormalizationContext: [
'groups' => ['user:input']
],
normalizationContext: [
'groups' => ['user:output']
]
)]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
#[Groups(['user:output'])]
/**
* L'identifiant d'un utilisateur
*/
private $id;
#[ORM\Column(type: 'string', length: 180, unique: true)]
#[Groups(['user:output', 'user:input', 'forgotten-password', 'read:command', 'user_update'])]
/**
* L'email d'un utilisateur
*
* @Assert\NotNull
* @Assert\Email(
* message = "L'email'{{ value }}' n'est pas valide."
* )
*/
private $email;
#[ORM\Column(type: 'json')]
#[Groups(['user:output', 'admin:input'])]
/** Le role d'un utilisateur */
private $roles = [];
#[ORM\Column(type: 'string')]
#[Groups(['user:input'])]
/**
* Le mot de passe d'un utilisateur
*
* @Assert\NotNull
* @Assert\NotBlank(
* normalizer = "trim"
* )
*
*/
private $password;
#[ORM\Column(type: 'string', length: 255)]
#[Groups(['user:output', 'user:input'])]
/**
* Le prénom d'un utilisateur
*
* @Assert\NotNull
* @Assert\NotBlank(
* normalizer = "trim"
* )
* @Assert\Length(
* min = 1,
* max = 50,
* minMessage = "Doit contenir {{ limit }} caractères minimum",
* maxMessage = "Doit contenir {{ limit }} caractères maximum"
* )
*/
private $firstname;
#[ORM\Column(type: 'string', length: 255)]
#[Groups(['user:output', 'user:input'])]
/**
* Le nom d'un utilisateur
*
* @Assert\NotNull
* @Assert\NotBlank(
* normalizer = "trim"
* )
* @Assert\Length(
* min = 1,
* max = 50,
* minMessage = "Doit contenir {{ limit }} caractères minimum",
* maxMessage = "Doit contenir {{ limit }} caractères maximum"
* )
*
*/
private $lastname;
#[ORM\OneToMany(mappedBy: 'owner', targetEntity: Command::class, orphanRemoval: true)]
#[Groups(['user:output'])]
/** Les commandes effectuées par un utilisateur */
private $commands;
#[ORM\Column(type: 'string', length: 255, nullable: true)]
#[Groups(['user:output', 'user:input'])]
/** L'adresse d'un utilisateur
*
* @Assert\NotBlank(
* normalizer = "trim"
* )
* @Assert\Length(
* min = 1,
* max = 255,
* minMessage = "Doit contenir {{ limit }} caractères minimum",
* maxMessage = "Doit contenir {{ limit }} caractères maximum"
* )
*
*/
private $address;
#[ORM\Column(type: 'string', length: 255, nullable: true)]
private $stripeToken;
#[ORM\Column(type: 'boolean')]
private $isVerified = false;
#[ORM\Column(type: 'datetime', nullable: true)]
private $tokenValidAfter;
public function __construct()
{
$this->commands = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(string $email): self
{
$this->email = $email;
return $this;
}
/**
* Un identifiant visuel qui représente cet utilisateur
*
* @see UserInterface
*/
public function getUserIdentifier(): string
{
return (string) $this->email;
}
/**
* @see UserInterface
*/
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER';
return array_unique($roles);
}
public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
/**
* @see PasswordAuthenticatedUserInterface
*/
public function getPassword(): string
{
return $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
/**
* @see UserInterface
*/
public function eraseCredentials()
{
// If you store any temporary, sensitive data on the user, clear it here
// $this->plainPassword = null;
}
public function getFirstname(): ?string
{
return $this->firstname;
}
public function setFirstname(string $firstname): self
{
$this->firstname = $firstname;
return $this;
}
public function getLastname(): ?string
{
return $this->lastname;
}
public function setLastname(string $lastname): self
{
$this->lastname = $lastname;
return $this;
}
/**
* @return Collection|Command[]
*/
public function getCommands(): Collection
{
return $this->commands;
}
public function addCommand(Command $command): self
{
if (!$this->commands->contains($command)) {
$this->commands[] = $command;
$command->setOwner($this);
}
return $this;
}
public function removeCommand(Command $command): self
{
if ($this->commands->removeElement($command)) {
// set the owning side to null (unless already changed)
if ($command->getOwner() === $this) {
$command->setOwner(null);
}
}
return $this;
}
public function getAddress(): ?string
{
return $this->address;
}
public function setAddress(?string $address): self
{
$this->address = $address;
return $this;
}
public function getStripeToken(): ?string
{
return $this->stripeToken;
}
public function setStripeToken(?string $stripeToken): self
{
$this->stripeToken = $stripeToken;
return $this;
}
public function getIsVerified(): ?bool
{
return $this->isVerified;
}
public function setIsVerified(bool $isVerified): self
{
$this->isVerified = $isVerified;
return $this;
}
public function getTokenValidAfter(): ?\DateTimeInterface
{
return $this->tokenValidAfter;
}
public function setTokenValidAfter(?\DateTimeInterface $tokenValidAfter): self
{
$this->tokenValidAfter = $tokenValidAfter;
return $this;
}
}
<?php
namespace App\DataPersister;
use ApiPlatform\Core\DataPersister\DataPersisterInterface;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
class UserDataPersister implements DataPersisterInterface
{
private $entityManager;
private $userPasswordEncoder;
public function __construct(EntityManagerInterface $entityManager, UserPasswordHasherInterface $userPasswordEncoder)
{
$this->entityManager = $entityManager;
$this->userPasswordEncoder = $userPasswordEncoder;
}
public function supports($data): bool
{
return $data instanceof User;
}
/**
* @param User $data
*/
public function persist($data)
{
if ($data->getPassword()) {
$data->setPassword(
$this->userPasswordEncoder->hashPassword($data, $data->getPassword())
);
$data->eraseCredentials();
}
$this->entityManager->persist($data);
$this->entityManager->flush();
}
public function remove($data)
{
$this->entityManager->remove($data);
$this->entityManager->flush();
}
}
您的問題是由於您的代碼 hash 已經哈希密碼,因此每次都會生成一個新密碼。
您必須添加和使用 plainPassword 屬性。
use Symfony\Component\Serializer\Annotation\SerializedName;
...
#[ORM\Column(type: 'string')]
/**
* Le mot de passe d'un utilisateur
*
* @Assert\NotNull
* @Assert\NotBlank(
* normalizer = "trim"
* )
*
*/
private $password;
#[Groups("user:input")]
#[SerializedName("password")]
private $plainPassword;
...
而在您的 UserDataPersister 中,請改用此 plainPassword。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.