API şeklinde dizayn edilen bu uygulamada, Basic Auth authentication kullanıyoruz ayrıca, login veya logout fonksiyonlarıda mevcut değil. Kullanıcılar sadece izinli oldukları adreslere girebilirler, aksi takdirde "401 Unauthorised" hatası alırlar. Kullanıcılar veritabanında tutuluyor.


Adresler, kullanıcılar ve ulaşım hakları



İletişim hakkı alan kullanıcı, sadece JSON istek gönderir ve sonuç olarak ya JSON ya da XML formatında cevap alabilir. Format istekteki adresin uzantısına students.json|.xml bakılarak karar verilir. Eğer uzantı belirtilmemişse, varsayılan olarak JSON kullanılır.


Security.yml


security:

encoders:
Api\SchoolBundle\Entity\User:
algorithm: bcrypt
cost: 12

role_hierarchy:
ROLE_STUDENT: ROLE_USER
ROLE_LECTURER: ROLE_USER
ROLE_ADMIN: ROLE_USER

providers:
user:
entity:
class: ApiSchoolBundle:User
property: username

firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false

secured:
pattern: ^/.*
stateless: true
http_basic:
realm: "School API"
provider: user

Routing.yml


api_school:
resource: "@ApiSchoolBundle/Controller/"
prefix: /1/
type: annotation

Controllers


StudentController


namespace Api\SchoolBundle\Controller;

use Api\SchoolBundle\Util\ApiUser;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
* @Route("/students", service="api_school.controller.student")
*/
class StudentController
{
private $apiUser;

public function __construct(ApiUser $apiUser)
{
$this->apiUser = $apiUser;
}

/**
* @param string $format
*
* @Security("has_role('ROLE_USER')")
* @Method({"GET"})
* @Route(".{format}", requirements={"format"="json|xml"}, defaults={"format"="json"})
*
* @return Response
*/
public function getAllAction($format)
{
$user = $this->apiUser->get();

return new Response(json_encode(['roles' => $user->getRoles(), 'response' => $format]));
}

/**
* @param string $format
* @param Request $request
*
* @Security("has_role('ROLE_ADMIN')")
* @Method({"POST"})
* @Route(".{format}", requirements={"format"="json|xml"}, defaults={"format"="json"})
*
* @return Response
*/
public function createOneAction(Request $request, $format)
{
$user = $this->apiUser->get();

return new Response(json_encode(['roles' => $user->getRoles(), 'response' => $format]));
}
}

LecturerController


namespace Api\SchoolBundle\Controller;

use Api\SchoolBundle\Util\ApiUser;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
* @Route("/lecturers", service="api_school.controller.lecturer")
*/
class LecturerController
{
private $apiUser;

public function __construct(ApiUser $apiUser)
{
$this->apiUser = $apiUser;
}

/**
* @param string $format
*
* @Security("has_role('ROLE_LECTURER')")
* @Method({"GET"})
* @Route(".{format}", requirements={"format"="json|xml"}, defaults={"format"="json"})
*
* @return Response
*/
public function getAllAction($format)
{
$user = $this->apiUser->get();

return new Response(json_encode(['roles' => $user->getRoles(), 'response' => $format]));
}

/**
* @param string $format
* @param Request $request
*
* @Security("has_role('ROLE_ADMIN')")
* @Method({"POST"})
* @Route(".{format}", requirements={"format"="json|xml"}, defaults={"format"="json"})
*
* @return Response
*/
public function createOneAction(Request $request, $format)
{
$user = $this->apiUser->get();

return new Response(json_encode(['roles' => $user->getRoles(), 'response' => $format]));
}
}

AdminController


namespace Api\SchoolBundle\Controller;

use Api\SchoolBundle\Util\ApiUser;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
* @Route("/admins", service="api_school.controller.admin")
*/
class AdminController
{
private $apiUser;

public function __construct(ApiUser $apiUser)
{
$this->apiUser = $apiUser;
}

/**
* @param string $format
*
* @Security("has_role('ROLE_ADMIN')")
* @Method({"GET"})
* @Route(".{format}", requirements={"format"="json|xml"}, defaults={"format"="json"})
*
* @return Response
*/
public function getAllAction($format)
{
$user = $this->apiUser->get();

return new Response(json_encode(['roles' => $user->getRoles(), 'response' => $format]));
}

/**
* @param string $format
* @param Request $request
*
* @Security("has_role('ROLE_ADMIN')")
* @Method({"POST"})
* @Route(".{format}", requirements={"format"="json|xml"}, defaults={"format"="json"})
*
* @return Response
*/
public function createOneAction(Request $request, $format)
{
$user = $this->apiUser->get();

return new Response(json_encode(['roles' => $user->getRoles(), 'response' => $format]));
}
}

Controllers.yml


services:

api_school.controller.student:
class: Api\SchoolBundle\Controller\StudentController
arguments:
- "@api_school.util.api_user"

api_school.controller.lecturer:
class: Api\SchoolBundle\Controller\LecturerController
arguments:
- "@api_school.util.api_user"

api_school.controller.admin:
class: Api\SchoolBundle\Controller\AdminController
arguments:
- "@api_school.util.api_user"

User entity


namespace Api\SchoolBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Serializable;
use Symfony\Component\Security\Core\User\UserInterface;

/**
* @ORM\Table(name="user",
* uniqueConstraints={
* @ORM\UniqueConstraint(name="username_unq", columns={"username"}),
* @ORM\UniqueConstraint(name="email_unq", columns={"email"})
* }
* )
* @ORM\Entity(repositoryClass="Api\SchoolBundle\Repository\UserRepository")
*/
class User implements UserInterface, Serializable
{
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;

/**
* @ORM\Column(name="username", type="string", length=100)
*/
private $username;

/**
* @ORM\Column(name="password", type="string", length=100)
*/
private $password;

/**
* @ORM\Column(name="email", type="string", length=100)
*/
private $email;

/**
* @ORM\Column(name="roles", type="array")
*/
private $roles;

/**
* @ORM\Column(name="is_active", type="boolean")
*/
private $isActive = true;

/**
* @return integer
*/
public function getId()
{
return $this->id;
}

public function getUsername()
{
return $this->username;
}

public function setUsername($username)
{
$this->username = $username;

return $this;
}

public function getPassword()
{
return $this->password;
}

public function setPassword($password)
{
$this->password = $password;

return $this;
}

public function getEmail()
{
return $this->email;
}

public function setEmail($email)
{
$this->email = $email;

return $this;
}

public function getIsActive()
{
return $this->isActive;
}

public function setIsActive($isActive)
{
$this->isActive = $isActive;

return $this;
}

public function getRoles()
{
return $this->roles;
}

public function setRoles(array $roles)
{
return $this->roles = $roles;
}

public function getSalt()
{
return null;
}

public function eraseCredentials()
{
}

public function serialize()
{
return serialize([$this->id, $this->username, $this->password]);
}

public function unserialize($serialized)
{
list ($this->id, $this->username, $this->password) = unserialize($serialized);
}
}

Veritabanındaki görüntü aşağıdaki gibidir.


CREATE TABLE IF NOT EXISTS `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`password` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`email` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`is_active` tinyint(1) NOT NULL,
`roles` longtext COLLATE utf8_unicode_ci NOT NULL COMMENT '(DC2Type:array)',
PRIMARY KEY (`id`),
UNIQUE KEY `username_unq` (`username`),
UNIQUE KEY `email_unq` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;

UserRepository


namespace Api\SchoolBundle\Repository;

use Doctrine\ORM\EntityRepository;

class UserRepository extends EntityRepository
{
}

services:

api_school.repository.user:
class: Api\SchoolBundle\Repository\UserRepository
factory: ["@doctrine.orm.entity_manager", "getRepository"]
arguments:
- Api\SchoolBundle\Entity\User

API'ye gönderilen her istek için aşağıdaki sorgu çalıştırılır. Eğer sadece username alanı değilde, onun haricinde farklı alanlar da kullanmak isterseniz, kendi sorgunuzu oluşturmanız gerekecektir. Daha fazla bilgi için Using a Custom Query to Load the User adresini ziyaret edin.


SELECT id, username, password, email, roles, is_active FROM user WHERE username = ? LIMIT 1 ["admin"] []

ApiUser servis


namespace Api\SchoolBundle\Util;

use Api\SchoolBundle\Entity\User;
use Api\SchoolBundle\Exception\ApiException;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

class ApiUser
{
private $tokenStorage;

public function __construct(
TokenStorageInterface $tokenStorage
) {
$this->tokenStorage = $tokenStorage;
}

/**
* @return User
*/
public function get()
{
$user = $this->tokenStorage->getToken()->getUser();
if (!$user instanceof User) {
throw new ApiException('API user cannot be found.');
}

return $user;
}
}

services:

api_school.util.api_user:
class: Api\SchoolBundle\Util\ApiUser
arguments:
- "@security.token_storage"

CreateUserCommand


This is the command we use to create users.


namespace Api\SchoolBundle\Command;

use Api\SchoolBundle\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;

class CreateUserCommand extends Command
{
private $entityManager;
private $userPasswordEncoder;

public function __construct(
EntityManagerInterface $entityManager,
UserPasswordEncoderInterface $userPasswordEncoder
) {
parent::__construct();

$this->entityManager = $entityManager;
$this->userPasswordEncoder = $userPasswordEncoder;
}

protected function configure()
{
$this
->setName('school:create-user')
->addOption(
'username',
null,
InputOption::VALUE_REQUIRED,
'The username of the user.'
)
->addOption(
'email',
null,
InputOption::VALUE_REQUIRED,
'The email of the user.'
)
->addOption(
'roles',
null,
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
'The roles of the user.'
);
}

protected function execute(InputInterface $input, OutputInterface $output)
{
$password = bin2hex(random_bytes(16));

$this->createUser($input, $password);
$this->outputCredentials($output, $input->getOption('username'), $password);
}

private function createUser(InputInterface $input, $password)
{
$user = new User();
$user->setUsername($input->getOption('username'));
$user->setEmail($input->getOption('email'));
$user->setRoles($input->getOption('roles'));
$password = $this->userPasswordEncoder->encodePassword($user, $password);
$user->setPassword($password);

$this->entityManager->persist($user);
$this->entityManager->flush();
}

private function outputCredentials(OutputInterface $output, $username, $password)
{
$output->writeln(PHP_EOL.'CREDENTIALS');
$output->writeln('-----------');
$output->writeln('Username: '.$username);
$output->writeln('Password: '.$password.PHP_EOL);
}
}

services:

api_school.command.create_user:
class: Api\SchoolBundle\Command\CreateUserCommand
arguments:
- "@doctrine.orm.entity_manager"
- "@security.password_encoder"
tags:
- { name: console.command }

Kullanıcılarımızı yaratalım.


$ app/console school:create-user --username="student" --email="s@s.com" --roles="ROLE_USER" --roles="ROLE_STUDENT"

CREDENTIALS
-----------
Username: student
Password: 7bac6226bc57bed59559853cc2769f0a

$ app/console school:create-user --username="lecturer" --email="l@l.com" --roles="ROLE_USER" --roles="ROLE_LECTURER"

CREDENTIALS
-----------
Username: lecturer
Password: 68e31a9c7f47de3f1bd95d04f19dd935

$ app/console school:create-user --username="admin" --email="a@a.com" --roles="ROLE_USER" --roles="ROLE_STUDENT" --roles="ROLE_LECTURER" --roles="ROLE_ADMIN"

CREDENTIALS
-----------
Username: admin
Password: 52bb7533ef8bcd523ca7dc09d6c8cd3d

Test


İsterseniz yukarıdaki kullanıcı adı ve şifrelerini kullanırsınız, isterseniz de Authorization kafa ekini kullanabilirsiniz. Aşağıdaki ekleri kontrol edebilirsiniz.


curl -v -X GET -u "student:7bac6226bc57bed59559853cc2769f0a" "http://192.168.50.10:8083/app_dev.php/1/students.xml"

curl -v -X GET -H "Authorization: Basic c3R1ZGVudDo3YmFjNjIyNmJjNTdiZWQ1OTU1OTg1M2NjMjc2OWYwYQ==" "http://192.168.50.10:8083/app_dev.php/1/students.xml"

curl -v -X POST -u "admin:52bb7533ef8bcd523ca7dc09d6c8cd3d" -H "Content-Type: application/json" -d '{"key_1": "value", "key_1": "value"}' "http://192.168.50.10:8083/app_dev.php/1/students.xml"

curl -v -X POST -H "Authorization: Basic YWRtaW46NTJiYjc1MzNlZjhiY2Q1MjNjYTdkYzA5ZDZjOGNkM2Q=" "Content-Type: application/json" -d '{"key_1": "value", "key_1": "value"}' "http://192.168.50.10:8083/app_dev.php/1/students.xml"