objetivo
Crie uma autorização separada no Symfony 5:
- Administrador - terá a entidade Admin , faça o login url / admin / login
- Usuário - terá uma entidade de usuário , URL de login / login
- Os dados de login não devem se sobrepor, não podemos fazer login como usuário na página / admin / login
- Duas entidades diferentes devem ser criadas
- Dois controladores diferentes devem ser criados para o login e dois Security diferentes
- Possibilidade de configurar o encaminhamento após autorização separadamente um do outro
- A capacidade de usar diferentes dados de autorização (por exemplo, para o usuário, queremos que os usuários digitem seu email / senha e para o administrador fornecer proteção adicional adicionando alguns recursos de Uuid
Por que este guia é necessário?
Minha tarefa foi dividir o formulário de login com a entidade Usuário em dois diferentes - para o usuário (usuário da entidade) e para o administrador (administrador da entidade) para a funcionalidade normal do painel de administração (neste caso, EasyAdmin).
Neste tutorial, descreverei o caminho inteiro passo a passo, começando com a instalação da estrutura em si e terminando com a criação de duas formas diferentes de autorização.
Especificações
- Windows 10
- OpenServer 5.3.7
- PHP 7.4
- MariaDB-10.2.12
- Symfony 5.1
O tutorial está atualizado no final de junho de 2020.
Etapa 0 - Instale o Symfony 5
Assumiremos que você instalou todos os componentes necessários, incluindo o Composer, no diretório raiz do OpenServer (... / domínios).
composer create-project symfony/website-skeleton auth_project
Etapa 1 - configurando o banco de dados
Crie um novo banco de dados, denomine auth_project, deixe a senha e o usuário serem mysql. Agora precisamos redefinir as configurações .env.
Deve ser assim:
# 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 ###
Etapa 2 - criando a entidade Usuário
Crie uma entidade Usuário, selecione o email como um valor exclusivo
php bin/console make:user

Etapa 3 - Criar uma entidade administrativa
Repetimos tudo o que é descrito na etapa anterior, em vez do nome da entidade Usuário, coloque Admin
Etapa 4 - prepare os jogos
Criaremos duas contas de teste, uma para Usuário e a segunda para Admin. Vamos usar o DoctrineFixturesBundle
Primeiro, você precisa colocá-lo
composer require --dev orm-fixtures
Após a instalação em / src, a pasta DataFixtures será exibida, na qual o arquivo AppFixtures.php já será criado
, renomeie-o para UserFixtures.php e adicione a funcionalidade necessária.
<?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();
}
}
O mesmo deve ser feito para o administrador - create 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();
}
}
Etapa 5 - faça o upload das migrações e acessórios para o banco de dados
As entidades foram criadas, registramos equipamentos, resta agora preencher tudo no banco de dados, as seguintes ações que realizo com cada alteração de entidades ou equipamentos
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 #
Etapa 6 - criar autorização
No console, prescrevemos
php bin/console make:auth
Definimos as configurações e nomes da seguinte maneira:
# 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 será atualizado e 3 arquivos serão criados
Etapa 7 - editar security.yaml
Após a criação da autorização, security.yaml fica assim:
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 }
Precisamos adicionar um novo provedor admin_user_provider e alterar as configurações dos firewalls .
Por fim , o arquivo security.yaml deve ficar assim:
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 }
Etapa 8 - renomeie o modelo login.html.twig
Isso precisa ser feito, pois recriaremos a autorização via make: auth.
Vamos nomear esse arquivo.
Etapa 9 - editar UserAuthSecurityController
O arquivo está localizado no caminho App \ Controller, já que alteramos o nome do modelo, isso deve ser alterado no controlador.
Qual deve ser o 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.');
}
}
Etapa 10 - crie uma segunda autorização
No console, escreva:
php bin/console make:auth
Como adicionamos um novo app_admin_provider , será solicitado que você escolha qual firewall deseja atualizar:

Depois de escolher um firewall, ofereça para selecionar Entity, selecione \ App \ Entity \ Admin:

Etapa 11 - renomeie o login.html.twig que acabamos de criar
Renomeie o recém-criado login.html.twig para admin-login.html.twig
Etapa 12 - editando o AdminAuthController que acabamos de criar
Alterar rota e nome do modelo:
<?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.');
}
}
Etapa 13 - edite o arquivo config / routes.yaml
Crie login_check e admin_login_check, que definimos nas configurações do firewall no arquivo config / packages / security.yaml
Como o arquivo config / routes.yaml deve se parecer:
#index:
# path: /
# controller: App\Controller\DefaultController::index
login_check:
path: /login_check
admin_login_check:
path: /admin/login_check
Etapa 14 - edite o arquivo templates / secutiry / user-login.html.twig
Adicione o atributo action à tag:
{% 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 %}
Etapa 15 - edite o arquivo templates / secutiry / admin-login.html.twig
Adicione o atributo action à tag:
{% 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 %}
Etapa 16 - iniciando o site
Para iniciar o site, primeiro defina web-server-bundle:
composer require symfony/web-server-bundle --dev ^4.4.2
Lançamos o site:
php bin/console server:run
Etapa 17 - testando a autorização para o usuário
Vá para a página 127.0.0.1 : 8000 / login.
Vemos o seguinte:

Efetuamos login usando o email user@example.com e a senha 123654.
Vemos que a autorização foi bem-sucedida:

Se você usar dados incorretos, ele eliminará o erro de credenciais inválidas.
Etapa 18 - testando a autorização para Admin
Vá para a página 127.0.0.1 : 8000 / admin / login.
Vemos o seguinte:

Efetuamos login usando o email admin@example.com e a senha 123654.
Aparentemente, tudo foi bem-sucedido:

se inserirmos dados incorretos ou se entrarmos em Usuário na página / admin / login - será gerado um erro nas credenciais inválidas. Para a página / login, a mesma coisa - insira os dados do Admin - haverá um erro.
Conclusão
Obrigado a todos que leram até o final, tentaram pintar o guia o mais detalhadamente possível, para que todos, se necessário, pudessem fazer algo semelhante.
Decidi escrever um tutorial depois de não encontrar instruções detalhadas para esta tarefa na documentação, guias ou discussões em inglês, sem mencionar os materiais em russo.