Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spring事件未触发_Java_Spring_Spring Security - Fatal编程技术网

Java Spring事件未触发

Java Spring事件未触发,java,spring,spring-security,Java,Spring,Spring Security,如果用户试图使用错误的凭据进行身份验证,我想记录。因此,我已将此事件侦听器类添加到我的项目中: import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationListener; import org.springframework.security.authentication.event.AuthenticationFailureBadCredenti

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

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版本:4.0.9
Spring安全版本:3.2.5(也试用了4.0.1)


编辑:

好的,我将Spring的日志级别设置为DEBUG,但没有设置。我搜索了“Listener”的每一个实例,日志表明AuthenticationFailureListener和AuthenticationSuccessListener的实例都是在没有任何错误的情况下创建的

我甚至把日志放进了diff工具(在替换了所有的时间和审查之后),并与一个代码版本进行了比较,其中FailureListener代码被注释掉了,但没有找到什么。如果需要,您可以自己搜索:

在页面底部,您将在左侧找到纯日志文本


编辑2:部分解决

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

@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);
}
这是故意的

Javadoc for
AbstractAuthenticationProcessingFilter
明确指出:

活动出版物:

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

(强调我的)

如果要明确发送身份验证失败事件,可以使用自定义的
AuthenticationFailureHandler
扩展
SimpleRuThenticationFailureHandler
,该方法将发送事件并调用基类
onAuthenticationFailure
方法

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

我用另一种方式工作

@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();
    }
}
通过这些更改,我的事件侦听器能够接收身份验证失败事件。 这与spring security 4.0.2.RELEASE和spring boot 1.2.5.RELEASE一起使用

希望能有帮助

使用Spring Security 3.2.8可以很好地工作。有关源代码,请参阅

您的密码:

@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!");
        }
    }
}
@Named
公共类AuthenticationSuccessListener实现ApplicationListener{
私有最终记录器Logger=LoggerFactory.getLogger(getClass());
@注入
私人用户服务用户;
@凌驾
ApplicationEvent上的公共无效(AbstractAuthenticationEvent){
if(InteractiveAuthenticationSuccessEvent的事件实例){
User=users.get(event.getAuthentication().getName());
布尔值isAdmin=user.getRole().equals(user.ROLE\u ADMIN);
logger.info((isAdmin?“Admin”:“User”)+“id为”+User.getIdLink()+“已成功登录!”);
}
}
}

是否设置了正确的组件扫描,以便将您的
AuthenticationFailureListener
创建为bean?启用Spring调试日志以验证它是否已实际创建。这将为您/我们提供更多信息以供使用。FailureListener与SuccessListener位于同一个包中,因此扫描应同时使用这两个包。我现在尝试调试日志,谢谢!仍然存在一个问题:
.formLogin().failureHandler(handler)
在错误凭据上中断生成的登录页面重定向(即使我在我的handlers构造函数中调用
super(“/login?error”)
)。这导致在名为“GMM”的DispatcherServlet中找不到URI为[/GMM/login]的HTTP请求的映射,并且在使用错误凭据时返回404页。我认为这只是处理程序的配置问题。您登录页面的URL是什么?如果您直接在浏览器中键入该URL(
http://host/context/xxx
),与结尾处的
相同?错误
?当前直接键入的登录页面URL不会改变任何行为/login?错误在所有情况下都返回404。好的,我无法解决问题,但可以通过使用自定义登录页来回避它。在我的情况下,我覆盖了
受保护的void configure(AuthenticationManagerBuilder auth)
以自定义我的
AuthenticationManager
,从而中断了此事件的发送。我需要添加
auth。authenticationEventPublisher(authenticationEventPublisher())
其中
authenticationEventPublisher()
是一个
@Bean
,它返回一个新的
DefaultAuthenticationEventPublisher()
。您可以发布整个示例吗?
@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();
    }
}
@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!");
        }
    }
}