Spring BadCredentials 事件未触发 [英] Spring BadCredentials Event not firing

查看:21
本文介绍了Spring BadCredentials 事件未触发的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果用户尝试使用错误的凭据进行身份验证,我想记录.因此,我已将此事件侦听器类添加到我的项目中:

I want to log if a user tries to authenticate with wrong credentials. Therefore i have added this event listener class to my project:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent;
import org.springframework.stereotype.Component;

@Component
public class AuthenticationFailureListener
        implements ApplicationListener<AuthenticationFailureBadCredentialsEvent>{

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

    @Override
    public void onApplicationEvent(AuthenticationFailureBadCredentialsEvent event) {
        System.out.println("test");
        logger.info("test2");
    }
}

问题是它根本不起作用.我使用 Spring Security 默认登录页面.该页面在使用错误凭据时显示错误凭据"错误,但我上面的方法没有被调用.我有一个非常相似的成功事件侦听器代码,效果很好:

Problem is it does not work at all. I use Spring Security default login page. The page shows "bad credentials" error when using wrong credentials, but my method above does not get called. I have very similar code for a success event listener, which works wonderfully:

@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!");
    }
}

这是我的 Spring Security Java 配置:

Here is my Spring Security Java Configuration:

@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();
    }
}

我不知道这里发生了什么,非常感谢帮助!

I have no clue whats going on here, help appreciated a lot!

Spring 版本:4.0.9
Spring Security 版本:3.2.5(也试过 4.0.1)

Spring version: 4.0.9
Spring Security version: 3.2.5 (also tried 4.0.1)

好的,我将 Spring 的日志级别设置为 DEBUG,但没有.我搜索了每次出现的监听器",日志指出 AuthenticationFailureListener 和 AuthenticationSuccessListeners 的实例已经创建,没有任何错误.

Okay, i set log level to DEBUG for Spring, but nothing. I searched for every occurance of "Listener" and the log states that instances of AuthenticationFailureListener as well as AuthenticationSuccessListeners have been created without any error.

我什至将日志放入 diff 工具中(在替换所有时间和审查之后)并与将 FailureListener 代码注释掉的代码版本进行比较,但没有找到任何东西.如果您愿意,可以自行搜索:
https://www.diffchecker.com/cwdn4sp4
在页面底部,您会在左侧找到纯日志文本.

I even put the log into diff tool (after replacing all times & censoring) and compared with a code version where FailureListener code is commented out, but didn't find something. You can search it yourself if you want to:
https://www.diffchecker.com/cwdn4sp4
On the bottom of the page you will find the plain log text on the left side.

Edit2:部分解决

Serges 解决方案有所帮助,这是我对 onAuthenticationFailure 方法的完整实现:​​

Serges solution helped, here is my complete implementation of the onAuthenticationFailure method:

@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);
}

推荐答案

那是设计.

AbstractAuthenticationProcessingFilter 的 Javadoc 对此很清楚:

Javadoc for AbstractAuthenticationProcessingFilter is clear on that :

活动发布:

如果身份验证成功,InteractiveAuthenticationSuccessEvent 将通过应用程序上下文发布.如果身份验证不成功,则不会发布任何事件,因为这通常会通过特定于 AuthenticationManager 的应用程序事件进行记录.

If authentication is successful, an InteractiveAuthenticationSuccessEvent will be published via the application context. No events will be published if authentication was unsuccessful, because this would generally be recorded via an AuthenticationManager-specific application event.

(强调我的)

如果您想为身份验证失败明确发送事件,您可以使用自定义 AuthenticationFailureHandler 扩展 SimpleUrlAuthenticationFailureHandler 将发送事件并调用基类 onAuthenticationFailure 方法.

If you want to send explicitely an event for authentication failures, you could use a custom AuthenticationFailureHandler extending SimpleUrlAuthenticationFailureHandler that would send the event and call base class onAuthenticationFailure method.

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);
    }
}

你应该可以这样配置:

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

@Autowired
AuthenticationFailureHandler eventAuthenticationFailureHandler;

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

这篇关于Spring BadCredentials 事件未触发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆