I’m working on an API, and I had implemented a JWT to make it stateless. I created an AuthController, which returns a JWT when login information is correct. Here you can see the return code that generates the token:
/* RETURN MESSAGE */ $body = [ 'auth_token' => $jwt, ]; $json = new JsonResponse($body); $json->setStatusCode(201, "Created"); // Headers return $json;
This is the result when I run the authenticate method, un the URL localhost:8000/authenticate
.
Now, what I would need to do is that, when a user tries to get another /
URL, the program doesn’t allow him to reach it if he’s not passing the Bearer token in the request’s header. But it’s not working. The platform always allows me to enter any URL without setting an Authorization in the header.
Here’s my security file, where I tried to set this:
security: # https://symfony.com/doc/current/security/authenticator_manager.html enable_authenticator_manager: true # https://symfony.com/doc/current/security.html#c-hashing-passwords password_hashers: SymfonyComponentSecurityCoreUserPasswordAuthenticatedUserInterface: 'auto' encoders: AppEntityATblUsers: algorithm: bcrypt providers: users_in_memory: { memory: null } firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false main: # Anonymous property is no longer supported by Symfony. It is commented by now, but it will be deleted in # future revision: # anonymous: true guard: authenticators: - AppSecurityJwtAuthenticator lazy: true provider: users_in_memory # activate different ways to authenticate # https://symfony.com/doc/current/security.html#firewalls-authentication # https://symfony.com/doc/current/security/impersonating_user.html # switch_user: true stateless: true # 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 } # - { path: ^/profile, roles: ROLE_USER }
And, finally, here’s my AppSecurityJwtAuthenticator
:
namespace AppSecurity; use DoctrineORMEntityManagerInterface; use SymfonyComponentDependencyInjectionParameterBagContainerBagInterface; use SymfonyComponentHttpFoundationJsonResponse; use SymfonyComponentHttpFoundationRequest; use SymfonyComponentHttpFoundationResponse; use SymfonyComponentSecurityCoreExceptionAuthenticationException; use SymfonyComponentSecurityCoreUserUserInterface; use SymfonyComponentSecurityCoreUserUserProviderInterface; use SymfonyComponentSecurityCoreAuthenticationTokenTokenInterface; use FirebaseJWTJWT; use SymfonyComponentSecurityGuardAbstractGuardAuthenticator; class JwtAuthenticator extends AbstractGuardAuthenticator { private $em; private $params; public function __construct(EntityManagerInterface $em, ContainerBagInterface $params) { $this->em = $em; $this->params = $params; } public function start(Request $request, AuthenticationException $authException = null): JsonResponse { $body = [ 'message' => 'Authentication Required', ]; return new JsonResponse($body, Response::HTTP_UNAUTHORIZED); } public function supports(Request $request): bool { return $request->headers->has('Authorization'); } public function getCredentials(Request $request) { return $request->headers->get('Authorization'); } public function getUser($credentials, UserProviderInterface $userProvider) { try{ $credentials = str_replace('Bearer ', '', $credentials); $jwt = (array) JWT::decode($credentials, $this->params->get('jwt_secret'), ['HS256']); return $this->em->getRepository('App:ATblUsers')->find($jwt['sub']); }catch (Exception $exception){ throw new AuthenticationException($exception->getMessage()); } } public function checkCredentials($credentials, UserInterface $user) { } public function onAuthenticationFailure(Request $request, AuthenticationException $exception): JsonResponse { return new JsonResponse([ 'message' => $exception->getMessage() ], Response::HTTP_UNAUTHORIZED); } public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey) { return; } public function supportsRememberMe(): bool { return false; } }
I’ve been looking at a lot of websites and tutorials, but not anyone is doing exactly what I need or are implementing very basic functionalities that don’t match with what I need. Almost all of that websites explain this using Symfony 4, but I’m using Symfony 5, so a lot of functions that use in tutorials are deprecated. Does someone know what I am missing?
Advertisement
Answer
You are probably missing access_control
configuration in security.yaml
:
security: # https://symfony.com/doc/current/security/authenticator_manager.html enable_authenticator_manager: true # https://symfony.com/doc/current/security.html#c-hashing-passwords password_hashers: SymfonyComponentSecurityCoreUserPasswordAuthenticatedUserInterface: 'auto' encoders: AppEntityATblUsers: algorithm: bcrypt providers: users_in_memory: { memory: null } firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false main: # Anonymous property is no longer supported by Symfony. It is commented by now, but it will be deleted in # future revision: # anonymous: true guard: authenticators: - AppSecurityJwtAuthenticator lazy: true provider: users_in_memory # activate different ways to authenticate # https://symfony.com/doc/current/security.html#firewalls-authentication # https://symfony.com/doc/current/security/impersonating_user.html # switch_user: true stateless: true # 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: ^/authenticate, roles: PUBLIC_ACCESS } - { path: ^/, roles: IS_AUTHENTICATED_FULLY }