I have a very weird behavior on symfony 6 with json login. Json login is configured like in their example.
I added the most simple Cors-handling
class CorsSubscriber implements EventSubscriberInterface
{
public function onKernelResponse(ResponseEvent $event)
{
$response = $event->getResponse();
$response->headers->add([
'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Headers' => 'Content-Type'
]);
}
public static function getSubscribedEvents()
{
return [
KernelEvents::RESPONSE => 'onKernelResponse',
];
}
}
Login Controller
class LoginController extends AbstractController
{
#[Route('/login', name: 'api_login')]
public function login(#[CurrentUser] ?User $user): JsonResponse
{
if ($user === null) {
$this->json([
'message' => 'Not found',
], JsonResponse::HTTP_UNAUTHORIZED);
}
$token = "token"; // some token logik follows
$response = new JsonResponse([
'user' => $user->getUserIdentifier(),
'token' => $token,
]);
return $response;
}
}
Again, basically straight out of their tutorial.
DB is also set up and a user was added beforehand. If I now want to login via a Rest App (I use Insomnia) everything works as expected. I get the user identifier (email) and token back.
But when I want to do the exact same thing via an Angular web app, I get the following message in the log: [critical] Uncaught Error: Call to a member function getUserIdentifier() on null
let data = {username: "[email protected]", password: "test123"};
this.http
.post('http://localhost:8000/login', data)
.subscribe({
next: (value) => {
console.log(value);
},
});
Funny thing since I check if $user is null...
But the most funny thing is, if I change the $user->getUserIdentifier()
call to just "$user
" - it works and I get the whole User object returned (everything I defined in json_serializable
)
Again, getUserIdentifier is from symfony itself
/**
* A visual identifier that represents this user.
*
* @see UserInterface
*/
public function getUserIdentifier(): string
{
return (string) $this->email;
}
What am I missing?
CodePudding user response:
In the documentation check_path: api_login
is defined in the "security.yaml ".
In the ApiLoginController #[route('/api/login', name:'api_login')]
I wanted to change this to the path "/login
".
Thereby I defined check_path: login
in security.yaml
and in the controller #[route('/login', name:'api_login')]
However, the name must also be "login", like #[route('/login', name:'login')]
CodePudding user response:
Found out what's wrong.
- No return
if ($user === null) {
$this->json([
'message' => 'Not found',
], JsonResponse::HTTP_UNAUTHORIZED);
}
I missed the return
before $this->json
, allowing the call to proceed even while $user
was indeed null
.
- Preflight Cors
I honestly don't have too much experience and knowledge about cors and wasn't really aware about the preflight calls being done. But that was the problem.
public function onKernelRequest(RequestEvent $event)
{
if (!$event->isMainRequest()) {
return;
}
$request = $event->getRequest();
$method = $request->getRealMethod();
if ('OPTIONS' == $method) {
$response = new Response();
$event->setResponse($response);
}
}
public static function getSubscribedEvents()
{
return [
KernelEvents::RESPONSE => ['onKernelResponse', 9999],
KernelEvents::REQUEST => ['onKernelRequest', 9999]
];
}
I extended the CorsSubscriber to check for Method OPTION
if it is not the main request and just sending a 200 to pass the preflight.
This helped me understand the logic behind it: