Especialista en Software
14 Jun 2019

API Rest con Symfony 4

API Rest con Symfony 4

Habilitar controladores API Rest

Instalar los siguientes paquetes:

jms/serializer-bundle
friendsofsymfony/rest-bundle
sensio/framework-extra-bundle

Configurar el archivo config/packages/fos_rest.yaml

fos_rest:
    routing_loader:
       default_format: json
       include_format: false
    body_listener: true
    format_listener:
       rules:
          - { path: '^/', priorities: ['json'], fallback_format: json, prefer_extension: false }
    param_fetcher_listener: true
    access_denied_listener:
       json: true
    view:
       view_response_listener: 'force'
       formats:
           json: true

 

Agregar estas lineas al archivo config/services.yaml

sensio_framework_extra.view.listener:
    alias: Sensio\Bundle\FrameworkExtraBundle\EventListener\TemplateListener

Controllador API Rest

<?php
namespace App\Controller;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use FOS\RestBundle\Controller\AbstractFOSRestController;
use FOS\RestBundle\Controller\Annotations as Rest;
use Symfony\Component\Routing\Annotation\Route;

/**
 * @Route("/")
 */
class IndexController extends AbstractFOSRestController
{
    /**
     * @Rest\Get("/")
     */
    public function index()
    {
        return [
            "service"   => "Mi API Rest",
            "version"   => "0.0.0",
            "status"    => "ok"
        ];
    }
}

Habilitar CORS

Instalar el siguiente paquete

composer req cors

Configurar config/packages/nelmio_cors.yaml

nelmio_cors:
    defaults:
        origin_regex: true
        allow_origin: ['%env(CORS_ALLOW_ORIGIN)%']
        allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE']
        allow_headers: ['Content-Type', 'Authorization']
        expose_headers: ['Link']
        max_age: 3600
    paths:
        '^/': ~

Habilitar autenticación JWT

Instalar el siguiente paquete

composer req "lexik/jwt-authentication-bundle"

Generar claves SSH

mkdir config/jwt
openssl genrsa -out config/jwt/private.pem -aes256 4096
openssl rsa -pubout -in config/jwt/private.pem -out config/jwt/public.pem

La contraseña asignada a la clave privada debe guardarse en la variable JWT_PASSPHRASE en el archivo .env.local

Agregar ruta de controlador de autenticación en config/routes.yml

login_check:
    path: /login_check
    methods: [POST]

Configurar seguridad en config/packages/security.yaml

security:
    encoders:
       App\Entity\User:
       algorithm: bcrypt

    providers:
       entity_provider:
          entity:
             class: App\Entity\User
                property: username

    firewalls:
       dev:
          pattern: ^/(_(profiler|wdt)|css|images|js)/
          security: false
       login:
          pattern: ^/login
          stateless: true
          anonymous: true
          json_login:
             check_path: /login_check
             success_handler: lexik_jwt_authentication.handler.authentication_success
             failure_handler: lexik_jwt_authentication.handler.authentication_failure
        api:
            pattern: ^/api
            stateless: true
            anonymous: false
            provider: entity_provider
            guard:
                authenticators:
                    - lexik_jwt_authentication.jwt_token_authenticator
        main:
            anonymous: true

    access_control:
        - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/api, roles: IS_AUTHENTICATED_FULLY }

Con esta configuración todas las rutas que empiecen por /api quedarán protegidas por la autenticación.

Crear un usuario

Los usuarios pueden crearse instanciando y persistiendo un objeto User. Para encriptar la contraseña  se debe inyectar la interface UserPasswordEncoderInterface. Este es un ejemplo de un método de registro dentro de un controlador:

/**
 * @Rest\Post("/register")
 */
public function register(Request $request, UserPasswordEncoderInterface $encoder)
{
    $em = $this->getDoctrine()->getManager();
        
    $username = $request->request->get('_username');
    $password = $request->request->get('_password');        

    $user = new User($username);
    $user->setPassword($encoder->encodePassword($user, $password));
    $em->persist($user);
    $em->flush();

    return [ "response" => sprintf('User %s successfully created', $user->getUsername()) ];
}

También se puede insertar un usuario en la base de datos directamente. Pero antes se debe generar una contraseña encriptada con el comando:

bin/console security:encode-password 'your_plain_password'

Autenticación con Postman

Obtener token

 

Enviar petición con token

Se debe agregar el header "Authorization" en la petición con el prefijo "Bearer" seguido de un espacio y el token obtenido en el paso anterior.

 

PHP • Symfony 2 Comments

2 comments :

  1. hola estaba siguiendo la guia y me tira el siguiente error al intentar ingresar a la ruta principal declarada en el controller

    Invalid type for path «fos_rest.routing_loader». Expected boolean, but got array.

    desde ya muchas gracias

Comments are closed.