Symfony 4 how to return invalid password instead of bad credentials on json login - symfony

So i use json login system on symfony 4 to log a user in, the default response from symfony with bad login details is 401, i didn't want that so i changed it to use a custom failure handler which returns a json response:
<?php
namespace App\Security;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
/**
* Class LoginFailureHandler
* #package App\Security
*/
class LoginFailureHandler implements AuthenticationFailureHandlerInterface
{
/**
* #param Request $request
* #param AuthenticationException $exception
* #return Response|void
*/
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
return new JsonResponse(['login'=>false,'valid'=>false,'message'=>$exception->getMessage()]);
}
}
This is all fine but the exception message says "Bad credentials", what i want is to be able to return either "invalid password" or "invalid username" depending on which one was found to be invalid.

Related

How to get the currently logged in User in EasyAdmin

How can I fetch the currently logged in User from anywhere within the Backend code? For example I have an EventSubscriber class and want to fetch it from there.
How can I do that w/o the help of i.e. AbstractController?
Symfony AbstractController is the core of most Controllers. Including EasyAdmin crud controller (XXXCrudController) extends AbstractController so you can access the same methods.
One of those is getUser() which return the current logged in user.
* Get a user from the Security Token Storage.
*
* #return UserInterface|null
*
* #throws \LogicException If SecurityBundle is not available
*
* #see TokenInterface::getUser()
*/
protected function getUser()
{
if (!$this->container->has('security.token_storage')) {
throw new \LogicException('The SecurityBundle is not registered in your application. Try running "composer require symfony/security-bundle".');
}
if (null === $token = $this->container->get('security.token_storage')->getToken()) {
return null;
}
// #deprecated since 5.4, $user will always be a UserInterface instance
if (!\is_object($user = $token->getUser())) {
// e.g. anonymous authentication
return null;
}
return $user;
}
So when trying to get the logged used in a controller, just use this method.
If you want to get the same thing, but for example in a service, you can basically do the same as what the method actually does by using the service injection with TokenStorageInterface to access the TokenStorage service which can get the current user.
So in your event subscriber, add TokenStorageInterface in your constructor to use it to first get the token and then your user. You may have to add another check to see if there is an user logged in (by checking if there is a token for example)
//YourService.php
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
private $tokenStorage
public function __construct(TokenStorageInterface $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
}
public function yourMethod()
{
//get token then user
$user = $tokenStorage->getToken()->getUser();
}

Symfony Invokable controllers called with render_esi

With Symfony, there is a possibility to create invokable controllers.
For some blocks like header or footer, i call my controller with twig function like this render(controller('App\\Controller\\MyInvokableController')) and it works.
But if i do the same with render_esi(controller('App\\Controller\\MyInvokableController')) i've this following error :
Cannot use object of type App\\Controller\\MyInvokableController as array
Is it possible to use invokable controller with render_esi ?
My controller :
declare(strict_types=1);
namespace App\Controller;
use ScemBundle\Helpers\EsiHelper;
use Symfony\Bridge\Twig\TwigEngine;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Twig\Error\Error;
/**
*
*/
final class MyInvokableController
{
use RepositoriesTrait;
/**
* #param Request $request
* #param EsiHelper $esiHelper
* #param TwigEngine $twig
*
* #return Response
* #throws Exception
*/
public function __invoke(Request $request, EsiHelper $esiHelper, TwigEngine $twig): Response
{
$params = $this->getSomeContent();
$content = $twig->render('#path/to/template.html.twig', $params);
$response = new Response();
$response
->setContent($content)
->setPublic()
->setSharedMaxAge(65536);
return $esiHelper->builEsiHeader($listItems, $response);
}
}

Expected response code "250/251/252" but got code "530", with message "530 SMTP authentication is required."

###> symfony/mailer ###
MAILER_DSN=smtp://localhost
###< symfony/mailer ###
this is a part from my .env i'm trying to send an email once the user is registred but i dont know wht to put in MAILER DSN, and i am getting this error
THE ERROR
and last but not least here's my mailer service
<?php
namespace App\Service;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Address;
class Mailer{
/**
* #var MailerInterface
*/
private $mailer;
public function __construct(MailerInterface $mailer)
{
$this->mailer = $mailer;
}
public function sendMail($email, $token){
$email = (new TemplatedEmail())
->from('Lost-found#foundonly.com')
->to(new Address($email))
->subject('Thanks for signing up! Just one more thing to do')
// path of the Twig template to render
->htmlTemplate('emails/signup.html.twig')
// pass variables (name => value) to the template
->context([
'token' => $token,
])
;
$this->mailer->send($email);
}
}
and finally the register controller
<?php
namespace App\Controller;
use App\Entity\User;
use App\Form\RegisterType;
use App\Service\Mailer;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
class RegisterController extends AbstractController
{
/**
* #var UserPasswordEncoderInterface
*/
private $passwordEncoder;
/**
* #var Mailer
*/
private $mailer;
public function __construct(UserPasswordEncoderInterface $passwordEncoder, Mailer $mailer)
{
$this->passwordEncoder = $passwordEncoder;
$this->mailer = $mailer;
}
/**
* #Route("/signup", name="signup")
* #throws \Exception
*/
public function register(Request $request): Response
{
$user = new User();
$form = $this->createForm(RegisterType::class,$user);
$form->handleRequest($request);
if($form->isSubmitted()&&$form->isValid()){
$user->setPassword(
$this->passwordEncoder->encodePassword($user,$form->get("password")->getData())
);
$user->setToken($this->generateToken());
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
$this->mailer->sendMail($user->getEmail(),$user->getToken());
$this->addFlash("success", "you are more than welcome into our community, just one more step | Check your mail please");
}//37.12
return $this->render('register/register.html.twig',[
'form' => $form->createView()
]);
}
/**
* #throws \Exception
*/
private function generateToken(): string
{
return rtrim(strtr(base64_encode(random_bytes(32)),'+/','-_'),'=');
}
}
?>
so please can anyone help me here? i really dont know wht to put in the mailer_dsn
You need to properly configure your Mailer transport. It can either be an SMTP server or local sendmail binary.
If you don't want to bother with sendmail and prefer using SMTP transport, the easiest solution would be using gmail smtp server with symfony/google-mailer component
More info:
Sending Emails with Mailer

Symfony/ Api platorm/JWT get the current user after login

Good morning to all
Please i need help. I am using JWT Authentication and all works well.But my problem is to retreive the current user after the login. I saw in the documentation that i can create a controller to do so, but after doing that i get the error of id parameter not given.
Here is my controller related to the user entity
// api/src/Controller/GetMeAction.php
namespace App\Controller;
use App\Entity\User;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Security;
class GetMeAction
{
/**
* #param Security
*/
private $_security;
public function __construct(Security $security)
{
$this->_security = $security;
}
/**
* #Route(
* name="get_me",
* path="get/me",
* methods={"GET"},
* defaults={
* "_api_resource_class"=User::class,
* "_api_item_operation_name"="get_me"
* }
* )
*/
public function __invoke(Request $request): User
{
return $this->_security->getUser();
}
}
Im using symfony 5.3, i wanted to use the api platform normalization and the item operation "get" to keep all the custom config, security, services, ...
So I used the forward() method in a controller :
/**
* #Route("/api/user/me", name="get_me")
*/
public function getMe(): Response
{
$router = $this->get('router')->getRouteCollection()->get('api_users_get_item');
$defaults = $router->getDefaults();
return $this->forward($router->getDefault('_controller'), array_merge($defaults, [ 'id' => $this->getUser()->getId()]));
}
Previous answer is right, but you forgot to Extend you controller from abstract one:
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class AdminController extends AbstractController
{
}
If you want to get User in the service, you can Inject Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface in your __construct()
and you can get user like:
public function getUser(): ?User
{
$token = $this->tokenStorage->getToken();
if (!$token) {
return null;
}
$user = $token->getUser();
if (!$user instanceof User) {
return null;
}
return $user;
}

FOSRestBundle : I can't see my new route

I've created a new controller (testController) which extends FOSRestController. I can't see the route "/test" i've created in this controller when I run symfony command "debug:router". With Postman, I've a 404 error...
I'm sure I forgot something but I don't know what. Here my code :
testController.php
<?php
namespace Project\ApiBundle\Controller;
use FOS\RestBundle\Controller\Annotations;
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\Controller\Annotations\Delete;
use FOS\RestBundle\Controller\Annotations\Get;
use FOS\RestBundle\Controller\Annotations\Post;
use FOS\RestBundle\Controller\Annotations\Put;
use FOS\RestBundle\Controller\FOSRestController;
use FOS\RestBundle\View\RouteRedirectView;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use JMS\Serializer\SerializationContext;
/**
* Class testController.
*/
class testController extends FOSRestController
{
/**
* List .
* #ApiDoc(
* resource = true,
* statusCodes = {
* 200 = "Returned when successful"
* }
* )
*
* #Rest\View()
* #Get("/test")
*
* #param Request $request the request object
*
* #return array
*/
public function getTest(Request $request)
{
return "hello world";
}
}
And, here my routing.yml file :
api_test:
type: rest
resource: Project\ApiBundle\Controller\TestController
What I've forgot ?
Thank you very much !
I finally found the answer... so easy but I didn't see it ! The method name :
=> getTestAction

Resources