21/12/2015 - SYMFONY
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, roller, username, password ve URIler "security.yml" içinde belirtilmişlerdir. Daha fazla bilgi için buraya tıklayın.
http://webservice.local/app_dev.php/
: IS_AUTHENTICATED_ANONYMOUSLY, ROLE_STUDENT, ROLE_LECTURER, ROLE_ADMINhttp://webservice.local/app_dev.php/api/student
: ROLE_STUDENT, ROLE_LECTURER, ROLE_ADMINhttp://webservice.local/app_dev.php/api/lecturer
: ROLE_LECTURER, ROLE_ADMINhttp://webservice.local/app_dev.php/api/admin
: ROLE_ADMINBir kullanıcıya birden fazla rol atamak için roles: [ROLE_STUDENT, ROLE_LECTURER, ROLE_ADMIN]
kullanabilirsiniz.
# app/config/security.yml
security:
# http://symfony.com/doc/current/book/security.html#encoding-the-user-s-password
encoders:
Symfony\Component\Security\Core\User\User:
algorithm: bcrypt
cost: 12
# http://symfony.com/doc/current/book/security.html#hierarchical-roles
role_hierarchy:
ROLE_STUDENT: ROLE_USER
ROLE_LECTURER: ROLE_STUDENT
ROLE_ADMIN: [ROLE_LECTURER, ROLE_ALLOWED_TO_SWITCH]
# http://symfony.com/doc/current/book/security.html#where-do-users-come-from-user-providers
providers:
in_memory:
memory:
users:
student:
password: $2a$10$GaEjFjAlt4R5Sc3.rGUAXu087b/hN/mQqe0oDLGAzBRIxinYuCVq2 # student
roles: ROLE_STUDENT
lecturer:
password: $2a$10$GEOb1t0g5QusbzaJwtRfqOuVJhQAzH5jcJt1m487UO.DsnUmd6ul2 # lecturer
roles: ROLE_LECTURER
admin:
password: $2a$10$GogNFjqLFM8vlopZTdl3te2EoVsgX9EGDOilodUige/syc5vKFFwO # admin
roles: ROLE_ADMIN
# the main part of the security, where you can set up firewalls
# for specific sections of your app
firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
# the default controller has to be accessible for everybody
unsecured:
pattern: ^/$
security: false
# secures part of the application
api_secured:
pattern: ^/api/
stateless: true
http_basic:
realm: "Inanzzz Webservice API"
provider: in_memory
# with these settings you can restrict or allow access for different parts
# of your application based on roles, ip, host or methods
# http://symfony.com/doc/current/cookbook/security/access_control.html
access_control:
- { path: ^/, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api/, role: ROLE_STUDENT }
Composer ile "jms/serializer-bundle" : "1.1.0"
kütüphanesini kurun ve new JMS\SerializerBundle\JMSSerializerBundle(),
satırını AppKernel dosyasına ekleyin.
# app/config/routing.yml
application_api:
resource: "@ApplicationApiBundle/Controller"
prefix: /
type: annotation
# app/config/services.yml
services:
doctrine_common_inflector:
class: Doctrine\Common\Inflector\Inflector
# src/Application/ApiBundle/Resources/config/controllers.yml
services:
application_api.controller.abstract:
class: Application\ApiBundle\Controller\AbstractController
abstract: true
arguments:
- @serializer
- @validator
- @doctrine_common_inflector
application_api.controller.default:
class: Application\ApiBundle\Controller\DefaultController
parent: application_api.controller.abstract
application_api.controller.api:
class: Application\ApiBundle\Controller\ApiController
parent: application_api.controller.abstract
namespace Application\ApiBundle\Controller;
use Doctrine\Common\Inflector\Inflector;
use JMS\Serializer\SerializationContext;
use JMS\Serializer\SerializerInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Validator\ConstraintViolationInterface;
use Symfony\Component\Validator\ConstraintViolationList;
use Symfony\Component\Validator\ConstraintViolationListInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
abstract class AbstractController
{
private $validContentTypes = ['json' => 'application/json', 'xml' => 'application/xml'];
protected $serializer;
protected $validator;
protected $inflector;
public function __construct(
SerializerInterface $serializer,
ValidatorInterface $validator,
Inflector $inflector
) {
$this->serializer = $serializer;
$this->validator = $validator;
$this->inflector = $inflector;
}
/**
* @param string $contentType
*
* @return string|Response
*/
protected function validateContentType($contentType)
{
if (!in_array($contentType, $this->validContentTypes)) {
return $this->createFailureResponse(
['content_type' => sprintf('Invalid content type [%s].', $contentType)],
'json',
Response::HTTP_UNSUPPORTED_MEDIA_TYPE
);
}
return array_search($contentType, $this->validContentTypes);
}
/**
* @param string $payload
* @param string $model
* @param string $format
*
* @return object|Response
*/
protected function validatePayload($payload, $model, $format)
{
$payload = $this->serializer->deserialize($payload, $model, $format);
$errors = $this->validator->validate($payload);
if (count($errors)) {
return $this->createFailureResponse($errors, $format);
}
return $payload;
}
/**
* @param array|object $content
* @param string $format
*
* @return Response
*/
protected function createSuccessResponse($content, $format = 'json')
{
return $this->getResponse($content, $format, Response::HTTP_OK);
}
/**
* @param array|ConstraintViolationListInterface $content
* @param string $format
*
* @return Response
*/
protected function createFailureResponse($content, $format = 'json')
{
$errorList = null;
if ($content instanceof ConstraintViolationList) {
foreach ($content as $error) {
$error = $this->getErrorFromValidation($error);
$errorList[$error['key']] = $error['value'];
}
} else {
$errorList = $content;
}
return $this->getResponse(['errors' => $errorList], $format, Response::HTTP_BAD_REQUEST);
}
/**
* @param array|object $content
* @param string $format
* @param int $status
*
* @return Response
*/
private function getResponse($content, $format, $status)
{
$context = new SerializationContext();
$context->setSerializeNull(false);
$response = $this->serializer->serialize($content, $format, $context);
return new Response($response, $status, ['Content-Type' => $this->validContentTypes[$format]]);
}
/**
* @param ConstraintViolationInterface $error
*
* @return array
*/
private function getErrorFromValidation($error)
{
$properties = $this->inflector->tableize($error->getPropertyPath());
return ['key' => $properties, 'value' => $error->getMessage()];
}
}
namespace Application\ApiBundle\Controller;
use Doctrine\Common\Inflector\Inflector;
use JMS\Serializer\SerializerInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Validator\Validator\ValidatorInterface;
/**
* @Route("", service="application_api.controller.default")
*/
class DefaultController extends AbstractController
{
public function __construct(
SerializerInterface $serializer,
ValidatorInterface $validator,
Inflector $inflector
) {
parent::__construct($serializer, $validator, $inflector);
}
/**
* @Method({"GET"})
* @Route("")
*
* @return Response
*/
public function indexAction()
{
return $this->createSuccessResponse('Welcome to Webservice API!');
}
}
Aşağıda göründüğü gibi diğer iki methoddan farklı olarak, studentAction
methodu için @Security
ekini tanımlamadık çünkü, security.yml içinde tanımlanan ulaşım hakları, login olan tüm kullanıcıların (ROLE_STUDENT, ROLE_LECTURER, ROLE_ADMIN) /api/...
adreslerine varsayılan olarak ulaşım hakkı veriyor. Bu varsayımı uygun bir biçimde çiğnemek için @Security
ekini kullanırız.
namespace Application\ApiBundle\Controller;
use Doctrine\Common\Inflector\Inflector;
use JMS\Serializer\SerializerInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Validator\Validator\ValidatorInterface;
/**
* @Route("api", service="application_api.controller.api")
*/
class ApiController extends AbstractController
{
public function __construct(
SerializerInterface $serializer,
ValidatorInterface $validator,
Inflector $inflector
) {
parent::__construct($serializer, $validator, $inflector);
}
/**
* @Method({"GET"})
* @Route("/student")
*
* @return Response
*/
public function studentAction()
{
return $this->createSuccessResponse('Hello ROLE_STUDENT user');
}
/**
* @Method({"GET"})
* @Route("/lecturer")
* @Security("has_role('ROLE_LECTURER')")
*
* @return Response
*/
public function lecturerAction()
{
return $this->createSuccessResponse('Hello ROLE_LECTURER user');
}
/**
* @Method({"GET"})
* @Route("/admin")
* @Security("has_role('ROLE_ADMIN')")
*
* @return Response
*/
public function adminAction()
{
return $this->createSuccessResponse('Hello ROLE_ADMIN user');
}
}
Tüm kullanıcılar /
adresine ulaşabilirler o nedenle bunun görselini aşağıda kullanmaya gerek yok. Ayrıca tüm adreslerin tüm kullanıcı ulaşım testleriyle ilgili kanıt olabilecek olan görsellerini kullanmaya da gerek yok ama, bana inanın ki uygulamamız doğru bir şekilde çalışıyor.
Hiçbir /api/...
adreslerine ulaşamaz.
Sadece /api/student
adresine ulaşabilir ama /api/lecturer
ve /api/admin
adreslerine ulaşamaz.
Sadece /api/student
ve /api/lecturer
adreslerine ulaşabilir ama /api/admin
adresine ulaşamaz.
Tüm /api/...
adreslerine ulaşabilir.