使用LDAP和DB在Symfony 5中进行多重身份验证 [英] Multiple authentication in Symfony 5 with LDAP and DB
问题描述
我想在Symfony 5中进行多重身份验证.第一个身份验证是LDAP.如果用户在里面就可以了.他将被连接.如果他不在,我想在用户存在的情况下在数据库中进行symfony检查.如果是,则将连接用户.
I woul'd like to do a multiple authentication in Symfony 5. The first authentication is LDAP. If the user is in it's ok. He will be connected. If he is not in I want symfony checks in DB if the user exists. If it's a yes so the user will be connected.
我尝试部署LDAP身份验证器和安全性验证器,但是...始终都是LDAP身份验证器起作用.永远没有安全感.
I tried to deploy LDAP authenticator and Security authenticator but... It's always LDAP authenticator who works. Never the security.
它如何工作以及我必须做什么?
How does it works and what I have to do ?
# app/config/services.yaml
# This file is the entry point to configure your own services.
# Files in the packages/ subdirectory configure your dependencies.
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
Symfony\Component\Ldap\Ldap:
arguments: ['@Symfony\Component\Ldap\Adapter\ExtLdap\Adapter']
Symfony\Component\Ldap\Adapter\ExtLdap\Adapter:
arguments:
- host: ldap.example.com
port: 389
#encryption: tls
options:
protocol_version: 3
referrals: false
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/*'
exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
# controllers are imported separately to make sure services can be injected
# as action arguments even if you don't extend any base controller class
App\Controller\:
resource: '../src/Controller'
tags: ['controller.service_arguments']
# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones
# app/config/packages/security.yaml
security:
encoders:
App\Entity\User:
algorithm: auto
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
my_ldap:
ldap:
service: Symfony\Component\Ldap\Ldap
base_dn: dc=example,dc=com
search_dn: cn=username,ou=Administration,dc=example,dc=com
search_password: userPassword
default_roles: ROLE_USER
app_user_provider:
entity:
class: App\Entity\User
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
ldap:
anonymous: ~
form_login_ldap:
login_path: login
check_path: login
service: Symfony\Component\Ldap\Ldap
dn_string: ou=aGroupWhereAreMyUsers,dc=example,dc=com
query_string: '(samaccountname={username})'
search_dn: cn=username,ou=Administration,dc=example,dc=com
search_password: userPassword
logout:
path: app_logout
main:
anonymous: ~
provider: app_user_provider
logout:
path: app_logout
guard:
authenticators:
- App\Security\LoginAuthenticator
access_control:
- { path: ^/$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/info$, roles: ROLE_USER }
role_hierarchy:
ROLE_SUPER_ADMIN: [ROLE_SUPER_ADMIN, ROLE_USER]
ROLE_USER: ROLE_USER
//app/src/Security/LoginAuthenticator.php
<?php
namespace App\Security;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
use Symfony\Component\Security\Guard\PasswordAuthenticatedInterface;
use Symfony\Component\Security\Http\Util\TargetPathTrait;
class LoginAuthenticator extends AbstractFormLoginAuthenticator implements PasswordAuthenticatedInterface
{
use TargetPathTrait;
public const LOGIN_ROUTE = 'login';
private $entityManager;
private $urlGenerator;
private $csrfTokenManager;
private $passwordEncoder;
public function __construct(EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder)
{
$this->entityManager = $entityManager;
$this->urlGenerator = $urlGenerator;
$this->csrfTokenManager = $csrfTokenManager;
$this->passwordEncoder = $passwordEncoder;
}
public function supports(Request $request)
{
return self::LOGIN_ROUTE === $request->attributes->get('_route')
&& $request->isMethod('POST');
}
public function getCredentials(Request $request)
{
$credentials = [
'email' => $request->request->get('email'),
'password' => $request->request->get('password'),
'csrf_token' => $request->request->get('_csrf_token'),
];
$request->getSession()->set(
Security::LAST_USERNAME,
$credentials['email']
);
return $credentials;
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
$token = new CsrfToken('authenticate', $credentials['csrf_token']);
if (!$this->csrfTokenManager->isTokenValid($token)) {
throw new InvalidCsrfTokenException();
}
$user = $this->entityManager->getRepository(User::class)->findOneBy(['email' => $credentials['email']]);
if (!$user) {
// fail authentication with a custom error
throw new CustomUserMessageAuthenticationException('Email could not be found.');
}
return $user;
}
public function checkCredentials($credentials, UserInterface $user)
{
return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
}
/**
* Used to upgrade (rehash) the user's password automatically over time.
*/
public function getPassword($credentials): ?string
{
return $credentials['password'];
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
return new RedirectResponse($targetPath);
}
// For example : return new RedirectResponse($this->urlGenerator->generate('some_route'));
throw new \Exception('TODO: provide a valid redirect inside '.__FILE__);
}
protected function getLoginUrl()
{
return $this->urlGenerator->generate(self::LOGIN_ROUTE);
}
}
//app/src/Controller/defaultController.php
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
class DefaultController extends AbstractController
{
/**
* @Route("/info", name="default")
*/
public function index()
{
return $this->render('default/index.html.twig', [
'controller_name' => 'DefaultController',
'user' => $this->getUser(),
]);
}
/**
* @Route("/", name="login")
*/
public function loginAction(Request $request, AuthenticationUtils $authUtils): Response
{
// get the login error if there is one
$error = $authUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authUtils->getLastUsername();
if(!is_null($this->getUser()) && in_array('CN=userHasToBeInThisGroupToAccessToTheWebsite,OU=Administration,DC=example,DC=com', $this->getUser()->getEntry()->getAttributes()['memberOf'])){
if(in_array('CN=groupWhereUsersWhoAreInAreAdmins,OU=Administration,DC=example,DC=com', $this->getUser()->getEntry()->getAttributes()['memberOf'])){
//Insert the code here to add "ROLE_SUPER_ADMIN" to the user before he goes on the dashboard
}
return $this->redirectToRoute('default');
}
return $this->render('security/login.html.twig', array(
'last_username' => $lastUsername,
'error' => $error,
));
}
/**
* @Route("/logout", name="app_logout")
*/
public function logout()
{
// controller can be blank: it will never be executed!
throw new \Exception('Don\'t forget to activate logout in security.yaml');
}
}
{# app/templates/security/login.html.twig #}
{% extends 'base.html.twig' %}
{% block body %}
{% if error %}
<div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}
<form method="post">
<label for="username">Username:</label>
<input type="text" id="username" name="_username" value="{{ last_username }}" required />
<label for="password">Password:</label>
<input type="password" id="password" name="_password" required />
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}" />
<button type="submit">login</button>
</form>
<a href='/logout'> Logout </a>
{% endblock %}
推荐答案
@Ping,您可以使用两个提供程序和两个防火墙,如下所示:
@Ping you can use two providers and two firewalls like below
providers:
db_provider:
entity:
class: UserBundle:User
property: username
hr_provider:
entity:
class: UserBundle:User
property: username
firewalls:
main:
provider: db_provider
pattern: ^/login|/logout|^/crm
anonymous: ~
form_login:
default_target_path: contact_index
login_path: login
check_path: login
logout:
path: logout
target: login
hr_main:
pattern: ^/signin|^/logoff|^/hr
anonymous: ~
provider: hr_provider
form_login:
default_target_path: hr_employee_leaves_balance
login_path: hr_signin
check_path: hr_signin
logout:
path: hr_logout
target: hr_signin
这篇关于使用LDAP和DB在Symfony 5中进行多重身份验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!