propósito
Crea una autorización por separado en Symfony 5:
- Administrador: tendrá la entidad de administración , URL de inicio de sesión / admin / login
- Usuario: tendrá una entidad de usuario , URL de inicio de sesión / inicio de sesión
- Los datos de inicio de sesión no deben superponerse, no podemos iniciar sesión como Usuario en la página / admin / login
- Deben crearse dos entidades diferentes.
- Se deben crear dos controladores de inicio de sesión diferentes y dos Seguridad diferentes
- Posibilidad de configurar el reenvío después de la autorización por separado
- La capacidad de usar diferentes datos de autorización (por ejemplo, para el Usuario queremos que los usuarios ingresen correo electrónico / contraseña, y para que el Administrador brinde protección adicional al agregar algún tipo de Uuid
¿Por qué se necesita esta guía?
Mi tarea consistía en dividir el formulario de inicio de sesión con la entidad Usuario en dos diferentes: para el usuario (entidad Usuario) y para el administrador (entidad Admin) para la funcionalidad normal del panel de administración (en este caso, EasyAdmin).
En este tutorial, describiré la ruta completa paso a paso, comenzando con la instalación del marco en sí y terminando con la creación de dos formas diferentes de autorización.
Especificaciones
- Windows 10
- OpenServer 5.3.7
- PHP 7.4
- MariaDB-10.2.12
- Symfony 5.1
El tutorial es relevante a finales de junio de 2020.
Paso 0 - Instala Symfony 5
Suponemos que ha instalado todos los componentes necesarios, incluido Composer en el directorio raíz de OpenServer (... / domains).
composer create-project symfony/website-skeleton auth_project
Paso 1 - configurando la base de datos
Cree una nueva base de datos, asígnele el nombre auth_project, deje que la contraseña y el usuario sean mysql. Ahora necesitamos redefinir la configuración de .env.
Debería ser así:
# In all environments, the following files are loaded if they exist,
# the latter taking precedence over the former:
#
# * .env contains default values for the environment variables needed by the app
# * .env.local uncommitted file with local overrides
# * .env.$APP_ENV committed environment-specific defaults
# * .env.$APP_ENV.local uncommitted environment-specific overrides
#
# Real environment variables win over .env files.
#
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
#
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration
###> symfony/framework-bundle ###
APP_ENV=dev
APP_SECRET=16cbb669c87ff9259c522ee2846cb397
#TRUSTED_PROXIES=127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
#TRUSTED_HOSTS='^(localhost|example\.com)$'
###< symfony/framework-bundle ###
###> symfony/mailer ###
# MAILER_DSN=smtp://localhost
###< symfony/mailer ###
###> doctrine/doctrine-bundle ###
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
# For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db"
# For a PostgreSQL database, use: "postgresql://db_user:db_password@127.0.0.1:5432/db_name?serverVersion=11&charset=utf8"
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
DATABASE_URL=mysql://mysql:mysql@127.0.0.1:3306/auth_project?serverVersion=mariadb-10.2.12
###< doctrine/doctrine-bundle ###
Paso 2: creación de la entidad de usuario
Cree la entidad Usuario, seleccione el correo electrónico como un valor único
php bin/console make:user
Paso 3: crear una entidad administrativa
Repetimos todo lo que se describe en el paso anterior, en lugar del nombre de la entidad Usuario, coloque Admin
Paso 4: preparar accesorios
Creemos 2 cuentas de prueba, una para Usuario y otra para Administrador. Usaremos DoctrineFixturesBundle
Primero debes ponerlo
composer require --dev orm-fixtures
Después de la instalación, la carpeta DataFixtures aparecerá en / src, en la que ya se habrá creado el archivo AppFixtures.php.
Cámbiele el nombre a UserFixtures.php y agréguele la funcionalidad necesaria.
<?php
namespace App\DataFixtures;
use App\Entity\User;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
class UserFixtures extends Fixture
{
private $encoder;
private $em;
public function __construct(UserPasswordEncoderInterface $encoder, EntityManagerInterface $entityManager)
{
$this->encoder = $encoder;
$this->em = $entityManager;
}
public function load(\Doctrine\Persistence\ObjectManager $manager)
{
$usersData = [
0 => [
'email' => 'user@example.com',
'role' => ['ROLE_USER'],
'password' => 123654
]
];
foreach ($usersData as $user) {
$newUser = new User();
$newUser->setEmail($user['email']);
$newUser->setPassword($this->encoder->encodePassword($newUser, $user['password']));
$newUser->setRoles($user['role']);
$this->em->persist($newUser);
}
$this->em->flush();
}
}
Lo mismo debe hacerse para el administrador: cree AdminFixtures.php
<?php
namespace App\DataFixtures;
use App\Entity\Admin;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
class AdminFixtures extends Fixture
{
private $encoder;
private $em;
public function __construct(UserPasswordEncoderInterface $encoder, EntityManagerInterface $entityManager)
{
$this->encoder = $encoder;
$this->em = $entityManager;
}
public function load(\Doctrine\Persistence\ObjectManager $manager)
{
$adminsData = [
0 => [
'email' => 'admin@example.com',
'role' => ['ROLE_ADMIN'],
'password' => 123654
]
];
foreach ($adminsData as $admin) {
$newAdmin = new Admin();
$newAdmin->setEmail($admin['email']);
$newAdmin->setPassword($this->encoder->encodePassword($newAdmin, $admin['password']));
$newAdmin->setRoles($admin['role']);
$this->em->persist($newAdmin);
}
$this->em->flush();
}
}
Paso 5: cargue las migraciones y los accesorios en la base de datos
Se crean las entidades, registramos los accesorios, ahora queda por completar todo en la base de datos, los siguientes pasos que llevo a cabo con cada cambio de entidades o accesorios
php bin/console doctrine:schema:drop --full-database --force # ,
php bin/console doctrine:migrations:diff # . !
php bin/console doctrine:migrations:migrate #
php bin/console doctrine:fixtures:load #
Paso 6: crear autorización
En la consola escribimos
php bin/console make:auth
Establecemos la configuración y los nombres de la siguiente manera:
# php bin/console make:auth
What style of authentication do you want? [Empty authenticator]:
[0] Empty authenticator
[1] Login form authenticator
> 1
The class name of the authenticator to create (e.g. AppCustomAuthenticator):
> UserAuthenticator
Choose a name for the controller class (e.g. SecurityController) [SecurityController]:
> UserAuthSecurityController
Do you want to generate a '/logout' URL? (yes/no) [yes]:
>
created: src/Security/UserAuthenticator.php
updated: config/packages/security.yaml
created: src/Controller/UserAuthSecurityController.php
created: templates/security/login.html.twig
Success!
Next:
- Customize your new authenticator.
- Finish the redirect "TODO" in the App\Security\UserAuthenticator::onAuthenticationSuccess() method.
- Review & adapt the login template: templates/security/login.html.twig.
Como resultado, security.yaml se actualizará y se crearán 3 archivos
Paso 7 - edite security.yaml
Después de crear la autorización, security.yaml se ve así:
security:
encoders:
App\Entity\User:
algorithm: auto
App\Entity\Admin:
algorithm: auto
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
entity:
class: App\Entity\Admin
property: email
# used to reload user from session & other features (e.g. switch_user)
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: true
lazy: true
provider: app_user_provider
guard:
authenticators:
- App\Security\UserAuthenticator
logout:
path: app_logout
# where to redirect after logout
# target: app_any_route
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#firewalls-authentication
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: true
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
# - { path: ^/admin, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
Necesitamos agregar un nuevo proveedor admin_user_provider y cambiar la configuración de los firewalls .
Finalmente , el archivo security.yaml debería verse así:
security:
encoders:
App\Entity\User:
algorithm: auto
App\Entity\Admin:
algorithm: auto
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
entity:
class: App\Entity\User
property: email
app_admin_provider:
entity:
class: App\Entity\Admin
property: email
# used to reload user from session & other features (e.g. switch_user)
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
admin_secured_area:
pattern: ^/admin
anonymous: ~
provider: app_admin_provider
form_login:
login_path: /admin/login
check_path: /admin/login_check
default_target_path: /admin/login
username_parameter: email
password_parameter: password
guard:
authenticators:
- App\Security\AdminAuthenticator
logout:
path: app_logout
# where to redirect after logout
target: /admin/login
user_secured_area:
pattern: ^/
anonymous: ~
provider: app_user_provider
form_login:
login_path: /login
check_path: /login_check
default_target_path: /login
username_parameter: email
password_parameter: password
logout:
path: app_logout
# where to redirect after logout
target: /login
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
# - { path: ^/admin, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
Paso 8: cambie el nombre de la plantilla login.html.twig
Esto debe hacerse, ya que volveremos a crear la autorización a través de make: auth.
Pongamos nombre a este archivo.
Paso 9: edición del UserAuthSecurityController
El archivo se encuentra en la ruta App \ Controller, ya que cambiamos el nombre de la plantilla, esto debe cambiarse en el controlador.
Cuál debería ser el controlador:
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
class UserAuthSecurityController extends AbstractController
{
/**
* @Route("/login", name="app_login")
*/
public function login(AuthenticationUtils $authenticationUtils): Response
{
// if ($this->getUser()) {
// return $this->redirectToRoute('target_path');
// }
// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('security/user-login.html.twig', ['last_username' => $lastUsername, 'error' => $error]);
}
/**
* @Route("/logout", name="app_logout")
*/
public function logout()
{
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
}
}
Paso 10: crear una segunda autorización
En la consola, escribe:
php bin/console make:auth
Como hemos agregado un nuevo app_admin_provider , se nos pedirá que elijamos qué firewall queremos actualizar:
Después de seleccionar el firewall, ofrezca seleccionar Entity, seleccione \ App \ Entity \ Admin:
Paso 11: cambie el nombre de login.html.twig que acabamos de crear
Cambie el nombre del login.html.twig recién creado a admin-login.html.twig
Paso 12 - editando el AdminAuthController que acabamos de crear
Cambiar ruta y nombre de plantilla:
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
class AdminAuthController extends AbstractController
{
/**
* @Route("/admin/login", name="app_admin_login")
*/
public function adminLogin(AuthenticationUtils $authenticationUtils): Response
{
// if ($this->getUser()) {
// return $this->redirectToRoute('target_path');
// }
// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('security/admin-login.html.twig', ['last_username' => $lastUsername, 'error' => $error]);
}
/**
* @Route("/logout", name="app_logout")
*/
public function logout()
{
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
}
}
Paso 13: edición del archivo config / routes.yaml
Cree login_check y admin_login_check, que definimos en la configuración del firewall en el
archivo config / packages / security.yaml Cómo debería verse el archivo config / routes.yaml:
#index:
# path: /
# controller: App\Controller\DefaultController::index
login_check:
path: /login_check
admin_login_check:
path: /admin/login_check
Paso 14: edite el archivo templates / secutiry / user-login.html.twig
Agregue el atributo de acción a la etiqueta:
{% extends 'base.html.twig' %}
{% block title %}Log in!{% endblock %}
{% block body %}
<form action="{{ path('login_check') }}" method="post">
{% if error %}
<div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}
{% if app.user %}
<div class="mb-3">
You are logged in as {{ app.user.username }}, <a href="{{ path('app_logout') }}">Logout</a>
</div>
{% endif %}
<h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
<label for="inputEmail">Email</label>
<input type="email" value="{{ last_username }}" name="email" id="inputEmail" class="form-control" required autofocus>
<label for="inputPassword">Password</label>
<input type="password" name="password" id="inputPassword" class="form-control" required>
<input type="hidden" name="_csrf_token"
value="{{ csrf_token('authenticate') }}"
>
{#
Uncomment this section and add a remember_me option below your firewall to activate remember me functionality.
See https://symfony.com/doc/current/security/remember_me.html
<div class="checkbox mb-3">
<label>
<input type="checkbox" name="_remember_me"> Remember me
</label>
</div>
#}
<button class="btn btn-lg btn-primary" type="submit">
Sign in
</button>
</form>
{% endblock %}
Paso 15: edite el archivo templates / secutiry / admin-login.html.twig
Agregue el atributo de acción a la etiqueta:
{% extends 'base.html.twig' %}
{% block title %}Log in!{% endblock %}
{% block body %}
<form action="{{ path('admin_login_check') }}" method="post">
{% if error %}
<div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}
{% if app.user %}
<div class="mb-3">
You are logged in as {{ app.user.username }}, <a href="{{ path('app_logout') }}">Logout</a>
</div>
{% endif %}
<h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
<label for="inputEmail">Email</label>
<input type="email" value="{{ last_username }}" name="email" id="inputEmail" class="form-control" required autofocus>
<label for="inputPassword">Password</label>
<input type="password" name="password" id="inputPassword" class="form-control" required>
<input type="hidden" name="_csrf_token"
value="{{ csrf_token('authenticate') }}"
>
{#
Uncomment this section and add a remember_me option below your firewall to activate remember me functionality.
See https://symfony.com/doc/current/security/remember_me.html
<div class="checkbox mb-3">
<label>
<input type="checkbox" name="_remember_me"> Remember me
</label>
</div>
#}
<button class="btn btn-lg btn-primary" type="submit">
Sign in
</button>
</form>
{% endblock %}
Paso 16: lanzamiento del sitio web
Para iniciar el sitio, primero instale el paquete de servidor web:
composer require symfony/web-server-bundle --dev ^4.4.2
Lanzamos el sitio:
php bin/console server:run
Paso 17: prueba de autorización para el usuario
Vaya a la página 127.0.0.1 : 8000 / login
Vemos esto: Iniciamos
sesión con el correo electrónico user@example.com y la contraseña 123654.
Vemos que la autorización fue exitosa:
si usa datos incorrectos, obtendrá el error de Credenciales no válidas.
Paso 18 - prueba de autorización para administrador
Vamos a la página 127.0.0.1 : 8000 / admin / login.
Vemos esto:
Inicie sesión con el correo electrónico admin@example.com y la contraseña 123654.
Parece que todo es exitoso:
si ingresa datos incorrectos o si ingresamos datos del Usuario en la página / admin / inicio de sesión: se producirá un error de credenciales no válidas. Para la página / login, lo mismo - ingrese los datos del administrador - habrá un error.
Conclusión
Gracias a todos los que leyeron hasta el final, trataron de escribir la guía con el mayor detalle posible, para que todos, si fuera necesario, pudieran hacer algo similar.
Decidí escribir un tutorial después de no poder encontrar instrucciones detalladas para esta tarea en la documentación, guías o debates en inglés, sin mencionar los materiales en ruso.