1
0
mirror of synced 2024-11-28 15:46:04 +03:00

Fix authenticators and dependecy injection

This commit is contained in:
Кривич Сергей 2022-07-21 13:02:32 +03:00
parent 6243bd1261
commit 180ccab466
8 changed files with 36 additions and 57 deletions

View File

@ -66,8 +66,8 @@ class RetailCrmServiceExtension extends Extension
$container
->register(CallbackValueResolver::class)
->setArguments([
new Reference($container->getParameter('retail_crm_service.request_schema.callback.serializer')),
new Reference('validator'),
new Reference($container->getParameter('retail_crm_service.request_schema.callback.serializer')),
$container->getParameter('retail_crm_service.request_schema.callback.supports')
])
->addTag('controller.argument_value_resolver', ['priority' => 50])
@ -76,8 +76,8 @@ class RetailCrmServiceExtension extends Extension
$container
->register(ClientValueResolver::class)
->setArguments([
new Reference($container->getParameter('retail_crm_service.request_schema.client.serializer')),
new Reference('validator'),
new Reference($container->getParameter('retail_crm_service.request_schema.client.serializer')),
$container->getParameter('retail_crm_service.request_schema.client.supports')
])
->addTag('controller.argument_value_resolver', ['priority' => 50])

View File

@ -23,12 +23,13 @@ security:
custom_authenticators:
- RetailCrm\ServiceBundle\Security\CallbackClientAuthenticator
front:
pattern: ^/(front|login)
pattern: ^/auth
provider: connection
stateless: false
remember_me:
secret: '%kernel.secret%'
lifetime: 604800 # 1 week in seconds
signature_properties: ['clientId']
always_remember_me: true
custom_authenticators:
- RetailCrm\ServiceBundle\Security\FrontApiClientAuthenticator
@ -41,33 +42,27 @@ security:
- { path: ^/simple-connection, roles: PUBLIC_ACCESS }
```
To authenticate the user after creating it, you can use the following code
Login controller will be called after the authenticator successfully authenticates the user. You can get the authenticated user, generate a token (or whatever you need to return) and return response:
```php
use App\Entity\Connection;
use App\Services\ConnectionManager;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Http\Authentication\UserAuthenticatorInterface;
use RetailCrm\ServiceBundle\Security\FrontApiClientAuthenticator;
use App\Entity\User;
use Symfony\Component\Security\Http\Attribute\CurrentUser;
class AppController extends AbstractController
class ApiLoginController extends AbstractController
{
public function someAction(
Request $request,
Connection $connection,
ConnectionManager $manager,
UserAuthenticatorInterface $userAuthenticator,
FrontApiClientAuthenticator $authenticator
): Response {
$exist = $manager->search($connection); //get connection
#[Route('/auth', name: 'auth')]
public function auth(#[CurrentUser] ?User $user): Response
{
$token = ...; // somehow create an API token for $user
$userAuthenticator->authenticateUser(
$connection,
$authenticator,
$request
);
return $this->json([
'user' => $user->getUserIdentifier(),
'token' => $token,
]);
}
}
```
The <code>#[CurrentUser]</code> can only be used in controller arguments to retrieve the authenticated user. In services, you would use getUser().

View File

@ -16,8 +16,6 @@ abstract class AbstractClientAuthenticator extends AbstractAuthenticator
{
public const AUTH_FIELD = 'clientId';
protected ObjectRepository $userRepository;
public function __construct(private ErrorJsonResponseFactory $errorResponseFactory)
{
}
@ -38,9 +36,4 @@ abstract class AbstractClientAuthenticator extends AbstractAuthenticator
{
return null;
}
public function setUserRepository(ObjectRepository $userRepository): void
{
$this->userRepository = $userRepository;
}
}

View File

@ -24,8 +24,7 @@ class CallbackClientAuthenticator extends AbstractClientAuthenticator
return new SelfValidatingPassport(
new UserBadge(
$identifier,
fn ($userIdentifier) => $this->userRepository->findOneBy([static::AUTH_FIELD => $userIdentifier])
$identifier
),
[]
);

View File

@ -38,8 +38,7 @@ class FrontApiClientAuthenticator extends AbstractClientAuthenticator
return new SelfValidatingPassport(
new UserBadge(
$identifier,
fn ($userIdentifier) => $this->userRepository->findOneBy([static::AUTH_FIELD => $userIdentifier]),
$identifier
),
[new RememberMeBadge()]
);

View File

@ -6,6 +6,8 @@ use Symfony\Component\Security\Core\User\UserInterface;
class User implements UserInterface
{
protected string $clientId = '123';
public function getRoles(): array
{
return ["USER"];
@ -22,6 +24,6 @@ class User implements UserInterface
public function getUserIdentifier(): string
{
return 'identifier';
return $this->clientId;
}
}

View File

@ -12,6 +12,7 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
class CallbackClientAuthenticatorTest extends TestCase
{
@ -58,19 +59,13 @@ class CallbackClientAuthenticatorTest extends TestCase
$errorResponseFactory = $this->createMock(ErrorJsonResponseFactory::class);
$user = new User();
$userRepository = $this->createMock(ObjectRepository::class);
$userRepository
->expects(static::once())
->method('findOneBy')
->willReturn($user)
;
$auth = new CallbackClientAuthenticator($errorResponseFactory);
$auth->setUserRepository($userRepository);
$passport = $auth->authenticate(new Request([], [CallbackClientAuthenticator::AUTH_FIELD => '123']));
$authUser = $passport->getUser();
static::assertEquals($user, $authUser);
static::assertTrue($passport->hasBadge(UserBadge::class));
static::assertEquals(
$user->getUserIdentifier(),
$passport->getBadge(UserBadge::class)->getUserIdentifier()
);
$this->expectException(AuthenticationException::class);
$auth->authenticate(new Request());

View File

@ -13,6 +13,7 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
class FrontApiClientAuthenticatorTest extends TestCase
{
@ -65,19 +66,14 @@ class FrontApiClientAuthenticatorTest extends TestCase
$security = $this->createMock(Security::class);
$user = new User();
$userRepository = $this->createMock(ObjectRepository::class);
$userRepository
->expects(static::once())
->method('findOneBy')
->with([FrontApiClientAuthenticator::AUTH_FIELD => '123'])
->willReturn($user)
;
$auth = new FrontApiClientAuthenticator($errorResponseFactory, $security);
$auth->setUserRepository($userRepository);
$passport = $auth->authenticate(new Request([], [FrontApiClientAuthenticator::AUTH_FIELD => '123']));
$authUser = $passport->getUser();
static::assertEquals($user, $authUser);
static::assertTrue($passport->hasBadge(UserBadge::class));
static::assertEquals(
$user->getUserIdentifier(),
$passport->getBadge(UserBadge::class)->getUserIdentifier()
);
$this->expectException(AuthenticationException::class);
$auth->authenticate(new Request());