Permalink
Browse files

Step 5. API Token authentication

  • Loading branch information...
nielsvandermolen committed Jun 12, 2018
1 parent 998e0c4 commit 46866acfd46eb5d188bd53181c20842140ff28d2
@@ -1,3 +1,8 @@
api_platform:
mapping:
paths: ['%kernel.project_dir%/src/Entity']
swagger:
api_keys:
apiKey:
name: X-AUTH-TOKEN
type: header
@@ -3,3 +3,4 @@ easy_admin:
# List the entity class name you want to manage
- App\Entity\Article
- App\Entity\Comment
- App\Entity\User
@@ -1,5 +1,9 @@
security:
providers:
user_db_provider:
entity:
class: App\Entity\User
property: apiKey
in_memory:
memory:
users:
@@ -12,6 +16,12 @@ security:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
api:
pattern: ^/api/
guard:
authenticators:
- App\Security\TokenAuthenticator
provider: user_db_provider
main:
http_basic: true
provider: in_memory
@@ -4,13 +4,20 @@
use App\Entity\Article;
use App\Entity\Comment;
use App\Entity\User;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\Persistence\ObjectManager;
class AppFixtures extends Fixture
{
public function load(ObjectManager $manager)
{
$user = new User();
$user->setApiKey('test_api_key');
$user->setUsername('test');
$user->setPassword('test');
$manager->persist($user);
for ($i = 0; $i < 10; $i++) {
$article = new Article();
$article->setBody('This is a body of article ' . $i);
@@ -0,0 +1,118 @@
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* @ORM\Table(name="app_users")
* @ORM\Entity(repositoryClass="App\Repository\UserRepository")
*/
class User implements UserInterface, \Serializable
{
/**
* @ORM\Id
* @ORM\Column(type="guid", unique=true)
* @ORM\GeneratedValue(strategy="UUID")
*/
private $id;
/**
* @ORM\Column(type="string", length=64, unique=true))
*/
private $apiKey;
/**
* @ORM\Column(type="string", length=25)
*/
private $username;
/**
* @ORM\Column(type="string", length=64)
*/
private $password;
public function getId()
{
return $this->id;
}
public function getApiKey(): ?string
{
return $this->apiKey;
}
public function setApiKey(string $apiKey): self
{
$this->apiKey = $apiKey;
return $this;
}
public function getUsername(): ?string
{
return $this->username;
}
public function setUsername(string $username): self
{
$this->username = $username;
return $this;
}
public function getPassword(): ?string
{
return $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
public function getSalt()
{
// you *may* need a real salt depending on your encoder
// see section on salt below
return null;
}
public function getRoles()
{
return array('ROLE_API');
}
public function eraseCredentials()
{
}
/** @see \Serializable::serialize() */
public function serialize()
{
return serialize(array(
$this->id,
$this->username,
$this->password,
$this->apiKey,
// see section on salt below
// $this->salt,
));
}
/** @see \Serializable::unserialize() */
public function unserialize($serialized)
{
list (
$this->id,
$this->username,
$this->password,
$this->apiKey,
// see section on salt below
// $this->salt
) = unserialize($serialized, ['allowed_classes' => false]);
}
}
@@ -0,0 +1,47 @@
<?php
namespace App\Repository;
use App\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Symfony\Bridge\Doctrine\RegistryInterface;
/**
* @method User|null find($id, $lockMode = null, $lockVersion = null)
* @method User|null findOneBy(array $criteria, array $orderBy = null)
* @method User[] findAll()
* @method User[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class UserRepository extends ServiceEntityRepository
{
public function __construct(RegistryInterface $registry)
{
parent::__construct($registry, User::class);
}
// /**
// * @return User[] Returns an array of User objects
// */
/*
public function findByApiKey($apiKey) {
return $this->createQueryBuilder('u')
->andWhere('u.apiKey = :apikey')
->setParameter('apikey', $apiKey)
->setMaxResults(1)
->getQuery()
->getResult();
}
*/
/*
public function findOneBySomeField($value): ?User
{
return $this->createQueryBuilder('u')
->andWhere('u.exampleField = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
*/
}
@@ -0,0 +1,93 @@
<?php
namespace App\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserProviderInterface;
class TokenAuthenticator extends AbstractGuardAuthenticator
{
/**
* Called on every request to decide if this authenticator should be
* used for the request. Returning false will cause this authenticator
* to be skipped.
*/
public function supports(Request $request)
{
return $request->headers->has('X-AUTH-TOKEN');
}
/**
* Called on every request. Return whatever credentials you want to
* be passed to getUser() as $credentials.
*/
public function getCredentials(Request $request)
{
return array(
'token' => $request->headers->get('X-AUTH-TOKEN'),
);
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
$apiKey = $credentials['token'];
if (null === $apiKey) {
return;
}
// if a User object, checkCredentials() is called
return $userProvider->loadUserByUsername($apiKey);
}
public function checkCredentials($credentials, UserInterface $user)
{
// check credentials - e.g. make sure the password is valid
// no credential check is needed in this case
// return true to cause authentication success
return true;
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
// on success, let the request continue
return null;
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
$data = array(
'message' => strtr($exception->getMessageKey(), $exception->getMessageData())
// or to translate this message
// $this->translator->trans($exception->getMessageKey(), $exception->getMessageData())
);
return new JsonResponse($data, Response::HTTP_FORBIDDEN);
}
/**
* Called when authentication is needed, but it's not sent
*/
public function start(Request $request, AuthenticationException $authException = null)
{
$data = array(
// you might translate this message
'message' => 'Authentication Required'
);
return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
}
public function supportsRememberMe()
{
return false;
}
}

0 comments on commit 46866ac

Please sign in to comment.