How can I get the username from a failed login using spring security?

风流意气都作罢 提交于 2020-01-20 13:36:02

问题


We're using spring security 3.0.5, Java 1.6 and Tomcat 6.0.32. In our .xml config file we've got:

<form-login login-page="/index.html" default-target-url="/postSignin.html" always-use-default-target="true"
 authentication-failure-handler-ref="authenticationFailureHandler"/>

and our authenticationFailureHandler defined as:

<beans:bean id="authenticationFailureHandler" class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler">
   <beans:property name="exceptionMappings">
      <beans:props>
    <beans:prop key="org.springframework.security.authentication.BadCredentialsException">/index.html?authenticationFailure=true</beans:prop>
    </beans:props>
   </beans:property>
</beans:bean>

Java

    @RequestMapping(params={"authenticationFailure=true"}, value ="/index.html")
    public String handleInvalidLogin(HttpServletRequest request) {
       //...  How can I get the username that was used???
       // I've tried:
       Object username = request.getAttribute("SPRING_SECURITY_LAST_USERNAME_KEY");
       Object username = request.getAttribute("SPRING_SECURITY_LAST_USERNAME");  // deprecated
    }

So we're directing all BadCredentialsExceptions to the index.html and IndexController. In the IndexController I'd like to get the username that was used for the failed login attempt. How can I do this?


回答1:


Okay so the answer turned out to be something extremely simple yet as far as I can tell, not greatly discussed or documented.

Here's all I had to do (no configurations anywhere just created this class)...

import org.apache.log4j.Logger;
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent;
import org.springframework.stereotype.Component;

@Component
public class MyApplicationListener implements ApplicationListener<AuthenticationFailureBadCredentialsEvent> {
    private static final Logger LOG = Logger.getLogger(MyApplicationListener.class);

    @Override
    public void onApplicationEvent(AuthenticationFailureBadCredentialsEvent event) {
        Object userName = event.getAuthentication().getPrincipal();
        Object credentials = event.getAuthentication().getCredentials();
        LOG.debug("Failed login using USERNAME [" + userName + "]");
        LOG.debug("Failed login using PASSWORD [" + credentials + "]");
    }
}

I'm far from a spring security expert so if anyone reads this and knows of a reason we shouldn't do it like this or knows a better way I'd love to hear about it.




回答2:


I did it this way:

  1. Created a class that extends SimpleUrlAuthenticationFailureHandler

  2. Overrid the onAuthenticationFailure method, which receives an HttpServletRequest as a parameter.

  3. request.getParameter("username"), where "username" is the name of my input in my HTML form.




回答3:


You could instead supply your own version of DefaultAuthenticationEventPublisher and override the publishAuthenticationFailure method.




回答4:


There doesn't seem to be much information on this solution, but if you set failureForwardUrl in your Spring Security configuration, you will be forwarded to the error page instead of redirected. You can then easily retrieve the username and password. For example, in your config add: .and().formLogin().failureForwardUrl("/login/failed") (* url must be different from the login page url)

And in your login controller, the following:

@RequestMapping(value = "/login/failed")
public String loginfailed(@ModelAttribute(UsernamePasswordAuthenticationFilter.SPRING_SECURITY_FORM_USERNAME_KEY) String user, @ModelAttribute(UsernamePasswordAuthenticationFilter.SPRING_SECURITY_FORM_PASSWORD_KEY) String password) {
     // Your code here
}

SPRING_SECURITY_FORM_USERNAME_KEY, SPRING_SECURITY_FORM_PASSWORD_KEY are the default names, but you can set these in the FormLoginConfigurer as well:

.and().formLogin().usernameParameter("email").passwordParameter("password").failureForwardUrl("/login/failed")



回答5:


I have found this works for me. Unfortunately, I still not found the exact location of this in SpringSecurity documents:

In any action, you can check the last-used username (no matter what the login was failed or not):

    String  username = (String) request.getSession().getAttribute("SPRING_SECURITY_LAST_USERNAME");



回答6:


If you want to use Spring AOP, you can add the below code to your Aspect class:

private String usernameParameter = "username"; 

@Before("execution(* org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler.onAuthenticationFailure(..))")
public void beforeLoginFailure(JoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = (HttpServletRequest) joinPoint.getArgs()[0];
        AuthenticationException exceptionObj = (AuthenticationException) joinPoint.getArgs()[2];

        String username = request.getParameter(usernameParameter);

        System.out.println(">>> Aspect check: AuthenticationException:  "+exceptionObj.getMessage());
        System.out.println(">>> Aspect check: user: "+ username + " failed to log in.");
}



回答7:


This is a pretty old thread, but if you are using a relatively current "spring-boot-starter-security" package, here's how I did it:

I set my AuthenticationFailureHandler like so:

SimpleUrlAuthenticationFailureHandler handler = new SimpleUrlAuthenticationFailureHandler("/my-error-url");
handler.setUseForward(true);

This will set the last exception into the request:

//from SimpleUrlAuthenticationFailureHandler source
request.setAttribute("SPRING_SECURITY_LAST_EXCEPTION", exception);

Then from my controller I can get the bad username:

RequestMapping("/impersonate-error")
public String impersonateErrorPage(Map<String, Object> model, HttpServletRequest request) {

    AuthenticationException ex = (AuthenticationException)request.getAttribute("SPRING_SECURITY_LAST_EXCEPTION");
    if(ex != null) {
        logger.debug("Impersonate message: " + ex.getMessage());
        model.put("badName", ex.getMessage());
    }
    return "impersonate-error";
}


来源:https://stackoverflow.com/questions/8676206/how-can-i-get-the-username-from-a-failed-login-using-spring-security

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!