Ich möchte verfolgen, wenn Benutzer sich in meiner Anwendung anmelden. Ich habe Code, den ich direkt nach der Authentifizierung des Benutzers ausführen möchte. Das Problem ist, ich kann nicht herausfinden, wo dies heißen soll. Bietet Spring-Security eine Möglichkeit, eine Methode nach der Authentifizierung aufzurufen?Spring-Security: Anrufmethode nach Authentifizierung
Antwort
Schreiben Sie Ihren eigenen SpringSecurityFilter und fügen Sie ihn direkt nach dem Aufruf Ihres Authentifizierungsanbieters zur Filterkette hinzu.
package my.code;
public class AuditFilter extends SpringSecurityFilter {
public void doFilterHttp(...) throws ... {
{application code to run before request is processed}
chain.doFilter(...);
{application code to run after request has fully processed}
}
}
Dann in Ihrer Konfiguration XML (wo immer Sie Setup der Sicherheitsfilterkette) eine Zeile wie diese hinzu:
<bean id="auditFilter" class="my.code.AuditFilter>
<security:custom-filter position="LAST"/> <-- you can change the position
</bean>
Dieser Link Post Authentication Logic auf ByteClip erklärt, wie eine gewisse Logik nach erfolgreicher Authentifizierung auszuführen, ohne zu stören Federsicherheitsfilterkette
Verbindung unterbrochen. ... – chrismarx
Die beste Möglichkeit besteht darin, einen Anwendungslistener zu erstellen und ihn mit dem Federsicherheitskontext zu registrieren.
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
public class AuthenticationSuccessListener implements ApplicationListener<InteractiveAuthenticationSuccessEvent> {
@Override
public void onApplicationEvent(InteractiveAuthenticationSuccessEvent event) {
System.out.println("User Logged In");
}
}
Stellen Sie sicher, die obige Klasse die Feder-security.xml als eine Bean hinzuzufügen. Es gibt viele andere Arten von Sicherheitsereignis-Listenern, die Sie anhören können. Überprüfen Sie die Typhierarchie auf eine Liste aller Arten von Sicherheitsereignissen, die Sie abhören können.
Je nach Situation, aber das wäre normalerweise mein Weg. Wenn Sie einen Nebeneffekt des Authentifizierungsereignisses erstellen müssen, verwenden Sie ApplicationListener. Wenn Sie angeben müssen, wie der Authentifizierungsprozess behandelt werden soll, verwenden Sie Handler. In diesem Fall "Tracking-Authentifizierungs-Aktion" würde ich für das Ereignis ebenso gehen, wie es eher ein Nebeneffekt ist. – wooki
wahrscheinlich sehr nützlich sein für jemanden ... Bei Frühling 3, konfigurieren Sicherheit:
<security:http use-expressions="true" auto-config="true">
<security:intercept-url pattern="..."/>
<security:form-login
authentication-failure-handler-ref="authFailureHandler"
authentication-success-handler-ref="authSuccessHandler"/>
<security:logout success-handler-ref="logoutSuccessHandler"
invalidate-session="true"/>
<security:session-management session-fixation-protection="newSession"/>
</security:http>
<bean id="authFailureHandler" class="mine.AuthenticationFailureHandlerImpl"/>
<bean id="authSuccessHandler" class="mine.AuthenticationSuccessHandlerImpl"/>
<bean id="logoutSuccessHandler" class="mine.LogoutSuccessHandlerImpl"/>
und eine entsprechende Klasse implementieren:
public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
//do what you want with
response.getOutputStream().write("success".getBytes());
}
}
Sie können Ressourcen verknüpfen über diese xml Konfig.
Gute Sachen! Danke für die Authentifizierung-success-handler-ref –
Wenn ich eine kleine Aktion hinzufügen und dann mit der normalen Handhabung fortfahren möchte, wie wäre es? – DiegoSahagun
Wenn Sie mit dem Standardverhalten fortfahren möchten, aber nur dazwischen Ihre eigene Geschäftslogik ausführen möchten, können Sie extend SimpleUrlAuthenticationSuccessHandler
eingeben und super.onAuthenticationSuccess(request, response, authentication);
aufrufen, bevor Sie zurückkehren. Weitere Details finden Sie unter https://stackoverflow.com/a/6770785/418439
Dies ist, was ich normalerweise tue, und ich empfehle es auch, wenn Sie nichts in der ursprünglichen Implementierung ändern müssen, aber einfach eine zusätzliche Funktionalität benötigen. Ich erstelle einen ChainAuthenticationSuccessHandler, der dann meinen eigenen Handler und einen der vorhandenen Handler wie 'SimpleUrlAuthenticationSuccessHandler' aufruft. Ich finde es zuverlässiger und sauberer als die Spring-Klasse zu verlängern. Ich denke, Sie könnten auch eine Art Decorator-Klasse über den ursprünglichen Handler erstellen, um Vererbung zu vermeiden, aber Kettenlösung spricht einfach besser zu mir. – wooki
Authentifizierung tut nicht unbedingt impliziert erfolgreiche Anmeldung. Ein Benutzer kann erfolgreich über z. B. bidirektionale SSL (X.509-Zertifikate) authentifiziert werden, und Spring Security leitet Sie dennoch zu einer Fehlerseite weiter, wenn die Verwaltung der Nebenperioden der Sitzung mit max-sessions="1"
eingerichtet wurde und dies ein zweiter gleichzeitiger Anmeldeversuch ist. Wenn Ihre Einrichtung einfach ist, ohne die Steuerung der Nebenläufigkeit von Sitzungen, können Sie login = authentication für alle praktischen Zwecke annehmen. Andernfalls, wenn Sie z. B. Logik haben, die alle erfolgreiche Anmeldung in einer Datenbank registriert, müssen Sie diese Logik an der Stelle der tatsächlichen Login aufrufen, nicht an der Stelle der Authentifizierung. Ein Weg (auf keinen Fall optimal, vorbehaltlich meines begrenzten Verständnisses des Spring Security Frameworks), dies zu tun, ist die Implementierung Ihres eigenen ConcurrentSessionControlAuthenticationStrategy
(klicken Sie auf here für den Quellcode) und injizieren Sie es in CompositeSessionAuthenticationStrategy
in Ihrer Spring Security (3.2 und höher) Konfiguration XML:
<http>
.
.
<session-management session-authentication-strategy-ref="sas" />
.
.
</http>
.
.
<beans:bean id="sas" class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
<beans:constructor-arg>
<beans:list>
<beans:bean class="path.to.my.implementation.of.ConcurrentSessionControlAuthenticationStrategy">
<beans:constructor-arg ref="sessionRegistry"/>
<beans:property name="maximumSessions" value="1"/>
<beans:property name="exceptionIfMaximumExceeded" value="true"/>
<beans:bean>
<beans:bean class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy"/>
<beans:bean class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy"/>
<beans:constructor-arg ref="sessionRegistry"/>
</beans:bean>
</beans:list>
</beans:constructor-arg>
</beans:bean>
<beans:bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl"/>
ich hätte lieber einen benutzerdefinierten PostLogin
Handler in den Rahmen des ConcurrentSessionControlAuthenticationStrategy
, statt Kopie-Einfügen von ihm in meine benutzerdefinierten ConcurrentSessionControlAuthenticationStrategy
und keine Änderungen an es zu injizieren, aber ich weiß nicht, einen Weg um dies im Moment zu tun.
Ein vollständigeres Konfigurationsbeispiel kann here gefunden werden.
Wenn Sie alle Thread vermeiden möchten Lesen: kuratiert Version mit Anmerkungen & ein bisschen mehr erklärend:
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component;
@Component
public class LoginSuccessListener implements ApplicationListener<AuthenticationSuccessEvent{
@Override
public void onApplicationEvent(AuthenticationSuccessEvent evt) {
// if you just need the login
String login = evt.getAuthentication().getName();
System.out.println(login + " has just logged in");
// if you need to access full user (ie only roles are interesting -- the rest is already verified as login is successful)
User user = (User) evt.getAuthentication().getPrincipal();
System.out.println(user.getUsername() + " has just logged in");
}
}
Bitte beachten Sie, dass SpringSecurityFilter zu den allgemeinen Spring Web GenericFilterBean in Spring Security geändert 3. –