So ziemlich alles ist im Titel.Zwei Firewalls mit zwei login_form und zwei verschiedenen AuthenticationSuccessHandlern, aber nur einer für beide
Ich komme hierher, um sicher zu sein, dass es sich um einen Fehler handelt, bevor es als Problem auf symfony/symfony gemeldet wird.
Ich habe folgendes security.yml:
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
providers:
in_memory:
memory:
users:
chalasr: { password: chalasr, roles: [ 'ROLE_USER' ] }
firewalls:
admin:
pattern: ^/admin
form_login:
provider: in_memory
login_path: /admin/login
check_path: /admin/login_check
failure_path: null
success_handler: admin.authentication_success_handler
logout:
path: /admin/logout
anonymous: true
login_api:
pattern: ^/v1/login
stateless: true
anonymous: true
form_login:
provider: in_memory
check_path: /v1/login_check
require_previous_session: false
username_parameter: username
password_parameter: password
success_handler: api.authentication_success_handler
api:
pattern: ^/v1/
stateless: true
lexik_jwt: ~
access_control:
- { path: ^/admin/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_USER }
- { path: ^/v1/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/v1/, role: ROLE_USER }
Wie Sie sehen können, habe ich zwei Login-Firewalls, eine für Routen mit ^/admin
und eine für die mit ^/v1
passend entsprechen.
Die beiden form_login
haben jeweilsauthentication_success_handler
gesetzt.
Die api-Handler:
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
class ApiAuthenticationSuccessHandler implements AuthenticationSuccessHandlerInterface
{
/**
* {@inheritdoc}
*/
public function onAuthenticationSuccess(Request $request, TokenInterface $token)
die('interecepted by api');
}
}
Der Admin-Handler:
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
class AdminAuthenticationSuccessHandler implements AuthenticationSuccessHandlerInterface
{
/**
* {@inheritdoc}
*/
public function onAuthenticationSuccess(Request $request, TokenInterface $token)
{
die('interecepted by admin');
}
}
Dienstleistungen:
admin.authentication_success_handler:
class: AppBundle\EventListener\AdminAuthenticationSuccessHandler
tags:
- { name: kernel.event_listener, event: security.on_authentication_success, method: onAuthenticationSuccess }
api.authentication_success_handler:
class: AppBundle\EventListener\ApiAuthenticationSuccessHandler
tags:
- { name: kernel.event_listener, event: security.on_authentication_success, method: onAuthenticationSuccess }
Das Problem ist, dass die admin.authentication_success_handler
die eine für beide Firewalls verwendet wird, ist es sagt überhaupt "admin abgefangen", für die api login route und für die admin login Route (Formular).
Mein erstes Ziel ist es auch Sachen zu machen, die völlig von der verwendeten Firewall abhängen, und dieses Verhalten verursacht einen Fehler in meiner Anwendung, wegen der Trennung admin/api.
Am Anfang, als ich den Fehler entdeckte, verwendete ich LexikJWTAuthenticationBundle und FOSUserBundle für die API und SonataAdminBundle (mit FOSUB) für den Admin, auf Symfony 2.8.
Dann habe ich auf 3.0 aufgerüstet und alle 3rd-Party-Security-Pakete entfernt, um jeden Zweifel daran zu vermeiden, und um sicher zu gehen, dass das von Symfony kommt. (Deshalb verwende ich einen einfachen Klartext-Encoder, so einfach wie möglich).
Bin ich richtig, wenn ich annehme, dass es ein Fehler ist? Oder mache ich einfach etwas falsch?
Weil das Ding offenbar noch nicht dokumentiert ist und wir viele verschiedene (funktionierende oder nicht) Implementierungen finden können.
EDIT
Hallo @tftd, danken die für Ihre Arbeit.
Es tut mir wirklich leid, aber ich habe auch meinen Code gekürzt, um die Frage lesbar zu machen, so dass die fehlenden anonymous: true
in den beiden ein einfacher Tippfehler von meiner Seite ist, fügte ich sie hinzu.
In der Tat funktioniert die Implementierung in einem Projekt, das abgeschlossen ist, ist es in einem API und einem Admin getrennt, beide auf verschiedenen Hosts, die Admin-Firewall mit einem Login-Formular von FOSUserBundle und die API-Firewall mit einem einfachen/login_check Endpunkt, der eine JWT bereitstellt, dann senden Benutzer authentifizierte Anforderungen an /v1/*
Routen mit dem Token als Header (Bearer).
Ich verbesserte auf 3.0, um in Phase zu sein, und ich verwendete eine einfache in_memory
, um irgendwelche Zweifel über 3rd Party Bundles zu vermeiden (FOSUserBundle Erfolgsbehandlung, LexikJWT Erfolgsverarbeitung oder irgendetwas anderes, das die Ursache des Fehlers sein kann), und ich hoffe, ich vermeide wirklich jeden Zweifel darüber Sie.
Sie können meine einfache routing.yml (bedenken Sie, dass ich das Problem mit einem Beispiel, das nur verwendet wird, um zu sehen, wie der Login-Erfolg zu verhalten, es ist absolut nicht eine reale Welt, aber ich komme aus dem gleichen Verhalten in einer realen Welt).
// app/config/routing.yml
fos_user:
prefix: /admin
resource: "@FOSUserBundle/Resources/config/routing/all.xml"
api_login_check:
path: /v1/login_check
Die Routen /admin/*
von FOSUserBundle verwaltet werden, die das Anmeldeformular zur Verfügung stellen, ist mein Ziel, wenn die beiden Login Erfolg sehen nur abgefangen werden, und in der Tat sind sie.
Das Problem kam aus, dass meine zwei Zuhörer auf security.interactive_login
zuhörte, es sah wie folgt aus:
class ApiAuthenticationSuccessHandler implements AuthenticationSuccessHandlerInterface
{
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
{
return $this->onAuthenticationSuccess($event->getRequest(), $event->getAuthenticationToken());
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token)
{
die('Interecepted by api');
}
}
Und die beiden Dienste Erklärungen ausgesehen:
api.authentication_success_handler:
class: AppBundle\EventListener\AuthenticationSuccessHandlerApi ]
tags:
- { name: kernel.event_listener, event: security.interactive_login, method: onSecurityInteractiveLogin }
mit den Tags gesetzt, nur ein Listener wird ausgelöst.
Durch Entfernen der Tags werden die entsprechenden Handler ordnungsgemäß an jeder Firewall aufgerufen.
Schlussfolgerung, keine Notwendigkeit der Tag ein AuthenticationSuccessListener (außer aus einem anderen Grund als die onAuthenticationSuccess werfen), und wenn Sie es markieren, markieren sie als security.on_authentication_success
Ereignis, nicht auf security.interactive_login
, weil, egal des Handlers definiert in security.yml, die erste wird bei InteractiveLogin verwendet und die zweite wird komplett ignoriert.
Vielen Dank @Federico für die gute Antwort und nochmals danke @tdtd.
Das Problem war, weil ich die 'security.on_interactive_login' verwendet habe, umAuthenticationSuccess manuell aufzurufen (siehe meine Bearbeitung). Wenn ich durch "security.on_authentication_success" wie in meiner Frage ersetzen, funktioniert alles gut. Wenn ich die Tags entferne, funktioniert alles gut, also gebe ich Ihnen den Punkt! t Danke – chalasr