问题描述
我想使用 DataProvider
来通过令牌重置密码。
我对 User
实体
"reset_password"={
* "method"="PATCH",* "path"="/user/{token}/password/reset",* "requirements"={"token"="^\w{32}$"},* "controller"=ResetPassword::class,* "normalization_context"={"groups"={"user:read"}},* "denormalization_context"={"groups"={"user-res-p:write"}},* "validation_groups"={"ResetPassword"},* "openapi_context"={
* "summary"="Reset della password dell'utente.",* "description"="Permette all'utente di modificare la sua password in caso l'abbia smarrita.<br>
Questo endpoint è aperto al pubblico e non necessita di autenticazione."
* }
* },
在请求的正文中客户端必须传递密码和confirmPassword
{
"plainPassword": "mynewpassword","confirmPassword": "mynewpassword"
}
这是我的控制器
namespace App\Controller\Security;
use App\Entity\Security\User;
use App\Repository\Security\UserRepository;
use Exception;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
class ResetPassword
{
/**
* @param string $token
* @param Request $request
* @param UserRepository $repository
* @param UserPasswordEncoderInterface $passwordEncoder
*
* @return User
* @throws Exception
*/
public function __invoke(User $data,Request $request,UserRepository $repository,UserPasswordEncoderInterface $passwordEncoder): User
{
$content = json_decode($request->getContent());
/** @var User $user */
//$user = $repository->getUserByResetPasswordToken($token);
$user = $data;
if(null === $user){
throw new NotFoundHttpException("Utente non trovato.");
}
$user->setPlainPassword($content->plainPassword);
$user->setConfirmPassword($content->confirmPassword);
$user->setPassword($passwordEncoder->encodePassword($user,$content->plainPassword));
$user->setRenewPasswordToken(null);
$user->setRenewPasswordTokenExpiration(null);
return $user;
}
}
但是我遇到了这个错误
{
"@context": "/api/contexts/Error","@type": "hydra:Error","hydra:title": "An error occurred","hydra:description": "Invalid identifier value or configuration.","trace": [
{
"namespace": "","short_class": "","class": "","type": "","function": "","file": "/path/to/project/vendor/api-platform/core/src/EventListener/ReadListener.PHP","line": 112,"args": []
},{
"namespace": "ApiPlatform\\Core\\EventListener","short_class": "ReadListener","class": "ApiPlatform\\Core\\EventListener\\ReadListener","type": "->","function": "onKernelRequest","file": "/path/to/project/vendor/symfony/event-dispatcher/Debug/WrappedListener.PHP","line": 117,{
"namespace": "Symfony\\Component\\Eventdispatcher\\Debug","short_class": "WrappedListener","class": "Symfony\\Component\\Eventdispatcher\\Debug\\WrappedListener","function": "__invoke","file": "/path/to/project/vendor/symfony/event-dispatcher/Eventdispatcher.PHP","line": 230,{
"namespace": "Symfony\\Component\\Eventdispatcher","short_class": "Eventdispatcher","class": "Symfony\\Component\\Eventdispatcher\\Eventdispatcher","function": "callListeners","line": 59,"function": "dispatch","file": "/path/to/project/vendor/symfony/event-dispatcher/Debug/TraceableEventdispatcher.PHP","line": 151,"short_class": "TraceableEventdispatcher","class": "Symfony\\Component\\Eventdispatcher\\Debug\\TraceableEventdispatcher","file": "/path/to/project/vendor/symfony/http-kernel/HttpKernel.PHP","line": 133,{
"namespace": "Symfony\\Component\\HttpKernel","short_class": "HttpKernel","class": "Symfony\\Component\\HttpKernel\\HttpKernel","function": "handleRaw","line": 79,"function": "handle","file": "/path/to/project/vendor/symfony/http-kernel/Kernel.PHP","line": 195,"short_class": "Kernel","class": "Symfony\\Component\\HttpKernel\\Kernel","file": "/path/to/project/public/index.PHP","line": 28,"args": []
}
]
}
数据提供者:
namespace App\DataProvider\Security;
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
use App\Entity\Security\User;
use App\Repository\Security\UserRepository;
class UserResetPasswordDataProvider implements ItemDataProviderInterface,RestrictedDataProviderInterface
{
private UserRepository $repository;
public function __construct(UserRepository $repository)
{
$this->repository = $repository;
}
public function getItem(string $resourceClass,$id,string $operationName = null,array $context = [])
{ dump($id);
return $this->repository->getUserByResetPasswordToken($id);
}
public function supports(string $resourceClass,array $context = []): bool
{
dump($resourceClass);
return User::class === $resourceClass && $operationName === 'reset_password';
}
}
解决方法
实际上,使用 API Platform 执行此操作的最佳方法是使用类似 /users/{id}/reset-password?hash=
的路由,以便 API P 可以为用户提供,然后您的工作只是检查访问权限。从 RESTFUL 的角度来看,它也更有意义。 (资源应在 URI 中标识)
您在此处遇到的错误是因为 API P 认为您在查询中拥有的哈希值是一个 id。探查器(可从 http://localhost/_profiler/ 获得)可能会告诉您更多关于此的信息,因为您之前有一个例外(滚动到例外页面的底部)。 >
不管怎样,问题很可能出在dataprovider上。您可以通过定义自己的方式来修复它。这个is documented here。这里有一个棘手的部分:您的数据提供者的设备的条件基于查询中发生的情况。因此,您的支持方法可能如下所示:
public function supports(string $resourceClass,string $operationName = null,array $context = []): bool
{
return User::class === $resourceClass && $this->requestStack->getMasterRequest()->has('hash');
}