2015-05-16 12 views
9

Ich möchte protokollieren, wenn ein Benutzer versucht, mit falschen Anmeldeinformationen zu authentifizieren. Daher habe ich diese Ereignis-Listener-Klasse zu meinem Projekt hinzugefügt:Spring BadCredentials Ereignis nicht ausgelöst

Problem ist es überhaupt nicht funktioniert. Ich benutze die Standard-Login-Seite von Spring Security. Die Seite zeigt den Fehler "falsche Anmeldeinformationen" an, wenn falsche Anmeldeinformationen verwendet werden. Die oben genannte Methode wird jedoch nicht aufgerufen. ich für einen Erfolg Ereignis-Listener sehr ähnlichen Code haben, die wunderbar funktioniert:

@Component 
public class AuthenticationSuccessListener implements 
     ApplicationListener<InteractiveAuthenticationSuccessEvent> { 

    private final Logger logger = LoggerFactory.getLogger(getClass()); 

    @Autowired private UserService users; 

    @Override 
    public void onApplicationEvent(InteractiveAuthenticationSuccessEvent event) { 
     User user = users.get(event.getAuthentication().getName()); 
     boolean isAdmin = user.getRole().equals(User.ROLE_ADMIN); 
     logger.info((isAdmin ? "Admin" : "User") + " with id " + user.getIdLink() 
       + " has successfully logged in!"); 
    } 
} 

Hier ist meine Spring Security Java-Konfiguration:

@Configuration 
@EnableWebMvcSecurity 
@EnableGlobalMethodSecurity(prePostEnabled=true) 
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{ 

    @Autowired 
    private CustomUserDetailsService userDetailsService; 

    @Bean 
    public PasswordEncoder passwordEncoder() { 
     return new BCryptPasswordEncoder(); 
    } 

    @Autowired 
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 
     auth 
      .userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); 
    } 

    protected void configure(HttpSecurity http) throws Exception { 
     http 
      .csrf().disable() 
      .formLogin() 
       .and() 
      .httpBasic(); 
    } 
} 

ich keine Ahnung, was hier los ist, Hilfe zu schätzen ein Menge!

Frühling Version: 4.0.9
Spring Security Version: 3.2.5 (auch 4.0.1 versucht)


Edit:

Okay, setze i -Protokollstufe für Spring debug, aber nichts. Ich habe nach jedem Vorkommen von "Listener" gesucht und im Protokoll steht, dass Instanzen von AuthenticationFailureListener und AuthenticationSuccessListeners fehlerfrei erstellt wurden.

Ich legte sogar das Protokoll in Diff-Tool (nach dem Ersetzen aller Zeiten & Zensur) und verglichen mit einer Code-Version, wo FailureListener Code auskommentiert ist, aber nicht etwas gefunden. Sie können es selbst suchen, wenn Sie möchten:
https://www.diffchecker.com/cwdn4sp4
Am unteren Rand der Seite finden Sie den einfachen Log-Text auf der linken Seite.


Edit2: Teil gelöst

Serges Lösung geholfen, hier ist meine komplette Umsetzung der onAuthenticationFailure Methode:

@Override 
public void onAuthenticationFailure(
     HttpServletRequest request, HttpServletResponse response, 
     AuthenticationException exception) throws IOException, ServletException { 

    if (exception instanceof BadCredentialsException) { 
     String name = request.getParameter("username"); 
     String password = request.getParameter("password"); 
     Authentication auth = 
       new UsernamePasswordAuthenticationToken(name, password); 
     eventPublisher.publishEvent(
       new AuthenticationFailureBadCredentialsEvent(auth, exception)); 
    } 
    super.onAuthenticationFailure(request, response, exception); 
} 
+0

Haben Sie die richtige Komponente Scan so eingerichtet haben, dass Ihre 'AuthenticationFailureListener' als Bean erstellt wird? Aktivieren Sie Spring Debug-Protokollierung, um zu überprüfen, dass es tatsächlich erstellt wird. Dadurch erhalten Sie/uns weitere Informationen, mit denen Sie arbeiten können. –

+0

Der FailureListener befindet sich im selben Paket wie der SuccessListener, daher sollte scan mit beiden funktionieren. Ill versuchen Debug-Logging jetzt, thx! – Katharsas

Antwort

6

Die nach Design ist.

Javadoc für AbstractAuthenticationProcessingFilter ist klar, dass:

Ereignis Publikation:

Wenn die Authentifizierung erfolgreich ist, wird ein InteractiveAuthenticationSuccessEvent über den Anwendungskontext veröffentlicht. Es werden keine Ereignisse veröffentlicht, wenn die Authentifizierung nicht erfolgreich war, da dies normalerweise über ein AuthenticationManager-spezifisches Anwendungsereignis aufgezeichnet würde.

(betonen Mine)

Wenn Sie explizit ein Ereignis für Authentifizierungsfehler senden möchten, können Sie eine benutzerdefinierte AuthenticationFailureHandler erstreckt SimpleUrlAuthenticationFailureHandler verwenden könnte, die das Ereignis senden würde und Basisklasse onAuthenticationFailure Methode aufrufen.

public class EventSendingAuthenticationFailureHandler 
     extends SimpleUrlAuthenticationFailureHandler, 
     implements ApplicationEventPublisherAware { 

    protected ApplicationEventPublisher eventPublisher; 

    public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) { 
     this.eventPublisher = eventPublisher; 
    } 

    @Override 
    void onAuthenticationFailure(javax.servlet.http.HttpServletRequest request, 
         javax.servlet.http.HttpServletResponse response, 
         AuthenticationException exception) 
         throws IOException, 
           javax.servlet.ServletException { 
     // use eventPublisher to publish the event according to exception 
     super.onAuthenticationFailure(request, response, exception); 
    } 
} 

sollten Sie in der Lage sein, es so zu konfigurieren:

@Bean 
AuthenticationFailureHandler eventAuthenticationFailureHandler() { 
    return new EventSendingAuthenticationFailureHandler(); 
} 

@Autowired 
AuthenticationFailureHandler eventAuthenticationFailureHandler; 

protected void configure(HttpSecurity http) throws Exception { 
    http 
     .csrf().disable() 
     .formLogin().failureHandler(eventAuthenticationFailureHandler) 
      .and() 
     .httpBasic(); 
} 
+0

Es gibt immer noch ein Problem: '.formLogin(). FailureHandler (handler)' bricht die generierte Umleitung der Login-Seite bei schlechten Zugangsdaten (auch wenn ich 'super (" login? Error ")' in meinem Handler-Konstruktor anrufe). Es führt zu 'Kein Mapping für HTTP-Anforderung mit URI [/ GMM/login] in DispatcherServlet mit dem Namen 'GMM' und eine 404-Seite wird zurückgegeben, wenn falsche Anmeldeinformationen verwendet werden. – Katharsas

+0

Ich denke, es ist nur ein Problem der Konfiguration des Handlers. Wie lautet die URL Ihrer Anmeldeseite? Was passiert, wenn Sie diese URL direkt in Ihrem Browser eingeben ("http: // host/context/xxx") und am Ende mit "? Error"? –

+0

Die URL meiner Anmeldeseite ist derzeit http: // localhost: 8080/GMM/login Die direkte Eingabe ändert kein Verhalten./login? Fehler gibt in allen Fällen ein 404 zurück. – Katharsas

9

ich diese Arbeit in einem anderen Weg.

@Configuration 
@EnableWebMvcSecurity 
@EnableGlobalMethodSecurity(prePostEnabled=true) 
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{ 

    // Inject applicationEventPublisher 
    @Inject 
    private ApplicationEventPublisher applicationEventPublisher; 

    @Autowired 
    private CustomUserDetailsService userDetailsService; 

    @Bean 
    public PasswordEncoder passwordEncoder() { 
     return new BCryptPasswordEncoder(); 
    } 

    @Autowired 
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 
     auth 
      // configure a auth event publisher 
      .authenticationEventPublisher(new DefaultAuthenticationEventPublisher(applicationEventPublisher)) 
      .userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); 
    } 

    protected void configure(HttpSecurity http) throws Exception { 
     http 
      .csrf().disable() 
      .formLogin() 
       .and() 
      .httpBasic(); 
    } 
} 

Mit diesen Änderungen konnte mein Ereignis-Listener Auth-Fehlerereignisse empfangen. Dies ist mit Feder-Sicherheit 4.0.2.RELEASE und Spring-Boot 1.2.5.RELEASE

Ich hoffe, es hilft.

+0

kannst du bitte das ganze Beispiel posten? – george

+0

Sie können JHipster (http://jhipster.github.io/) verwenden, um eine Beispielanwendung zu generieren. – krishnakumarp

0

Die LoggerListener funktioniert gut mit Spring Security 3.2.8. Siehe Grepcode für den Quellcode.

Ihr adpoted Code:

@Named 
public class AuthenticationSuccessListener implements ApplicationListener<AbstractAuthenticationEvent> { 

    private final Logger logger = LoggerFactory.getLogger(getClass()); 

    @Inject 
    private UserService users; 

    @Override 
    public void onApplicationEvent(AbstractAuthenticationEvent event) { 

     if (event instanceof InteractiveAuthenticationSuccessEvent) { 

      User user = users.get(event.getAuthentication().getName()); 
      boolean isAdmin = user.getRole().equals(User.ROLE_ADMIN); 
      logger.info((isAdmin ? "Admin" : "User") + " with id " + user.getIdLink() + " has successfully logged in!"); 
     } 
    } 
} 
Verwandte Themen