【问题标题】:DefaultAuthenticationEventPublisher not fire event to my @EventListenerDefaultAuthenticationEventPublisher 不会向我的@EventListener 触发事件
【发布时间】:2021-01-10 07:10:00
【问题描述】:

我有一个简单的 spring boot 应用程序,它使用带有 jwt 过滤器的 spring security

一切正常,但是当我尝试在侦听器中捕获身份验证成功和失败事件时,

它不起作用,身份验证事件从未触发我无法找到问题所在

这是我的安全类配置:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
@FieldDefaults(level = PRIVATE, makeFinal = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private static final RequestMatcher PUBLIC_URLS = new OrRequestMatcher(
            new AntPathRequestMatcher("/public/**"),
            new AntPathRequestMatcher("/h2-console/**"),
            new AntPathRequestMatcher("/v3/api-docs/**"),
            new AntPathRequestMatcher("/swagger-ui/**"),
            new AntPathRequestMatcher("/swagger-ui.html")
    );
    private static final RequestMatcher PROTECTED_URLS = new NegatedRequestMatcher(PUBLIC_URLS);

    TokenAuthenticationProvider provider;


    SecurityConfig(final TokenAuthenticationProvider provider) {
        super();
        this.provider = requireNonNull(provider);
    }

 /*   @Override
    protected void configure(final AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(provider);
    }*/

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationEventPublisher(authenticationEventPublisher());
    }
    @Override
    public void configure(final WebSecurity web) {
        web.ignoring().requestMatchers(PUBLIC_URLS);
    }

    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        http
                .sessionManagement()
                .sessionCreationPolicy(STATELESS)
                .and()
                .exceptionHandling()
                // this entry point handles when you request a protected page and you are not yet
                // authenticated
                .defaultAuthenticationEntryPointFor(forbiddenEntryPoint(), PROTECTED_URLS)
                .and()
                .authenticationProvider(provider)
                .addFilterBefore(restAuthenticationFilter(), AnonymousAuthenticationFilter.class)
                .authorizeRequests()
                .requestMatchers(PROTECTED_URLS)
                .authenticated()
                .and()
                .csrf().disable()
                .formLogin().disable()
                .httpBasic().disable()
                .logout().disable();

                // h2 console config
                http.headers().frameOptions().sameOrigin();
    }

    @Bean
    TokenAuthenticationFilter restAuthenticationFilter() throws Exception {
        final TokenAuthenticationFilter filter = new TokenAuthenticationFilter(PROTECTED_URLS);
        filter.setAuthenticationManager(authenticationManager());
        filter.setAuthenticationSuccessHandler(successHandler());
        return filter;
    }
    @Bean
    public DefaultAuthenticationEventPublisher authenticationEventPublisher() {
        return new DefaultAuthenticationEventPublisher();
    }
    @Bean
    SimpleUrlAuthenticationSuccessHandler successHandler() {
        final SimpleUrlAuthenticationSuccessHandler successHandler = new SimpleUrlAuthenticationSuccessHandler();
        successHandler.setRedirectStrategy(new NoRedirectStrategy());
        return successHandler;
    }

    @Bean
    PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    /**
     * Disable Spring boot automatic filter registration.
     */
    @Bean
    FilterRegistrationBean disableAutoRegistration(final TokenAuthenticationFilter filter) {
        final FilterRegistrationBean registration = new FilterRegistrationBean(filter);
        registration.setEnabled(false);
        return registration;
    }

    @Bean
    AuthenticationEntryPoint forbiddenEntryPoint() {
        return new HttpStatusEntryPoint(FORBIDDEN);
    }

我的 TokenAuthenticationFilter 是接口的实现:AbstractAuthenticationProcessingFilter

这是我的听众:

@Slf4j
@Component
@RequiredArgsConstructor
public class AuthenticationFailureListener {

    private final LoginFailureRepository loginFailureRepository ;
    private final UserRepository userRepository;

    @EventListener
    public void listen(AuthenticationFailureBadCredentialsEvent event){
        log.info("Login Failed");
        LoginFailure.LoginFailureBuilder builder = LoginFailure.builder();
        if(event.getSource() instanceof UsernamePasswordAuthenticationToken){
            UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) event.getSource();
            if(token.getPrincipal() instanceof String){
                String userName =(String) token.getPrincipal();
                builder.userName(userName);
                log.info("Attempted username : {}",userName);
                userRepository.findByUsername(userName).ifPresent(builder::user);
            }
            if(token.getPrincipal() instanceof WebAuthenticationDetails){
                WebAuthenticationDetails details =(WebAuthenticationDetails) token.getDetails();
                builder.sourceIp(details.getRemoteAddress());
                log.info("User remote address : {}",details.getRemoteAddress());
            }
        }
        LoginFailure loginFailure = loginFailureRepository.save(builder.build());
        log.info("saving login failure : {}",loginFailure);

    }
}

@Slf4j
@Component
@RequiredArgsConstructor
public class AuthenticationSuccessListener {

    private final LoginSuccessRepository loginSuccessRepository ;

    @EventListener
    public void listen(AuthenticationSuccessEvent event){
        log.info("--------------- USER LOGGED WITH SUCCESS ----------------------");

        LoginSuccess.LoginSuccessBuilder builder = LoginSuccess.builder();

        if(event.getSource() instanceof UsernamePasswordAuthenticationToken){
            UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) event.getSource();
            if(token.getPrincipal() instanceof User){
                User user =(User) token.getPrincipal();
                builder.user(user);
                log.info("User name login in : {}",user.getUsername());
            }
            if(token.getPrincipal() instanceof WebAuthenticationDetails){
                WebAuthenticationDetails details =(WebAuthenticationDetails) token.getDetails();
                builder.sourceIp(details.getRemoteAddress());
                log.info("User remote address : {}",details.getRemoteAddress());
            }
        }
        LoginSuccess loginSuccess = loginSuccessRepository.save(builder.build());

        log.info("saving login success : {}",loginSuccess);

    }


}

这是我的开始日志:

 SecurityAutoConfiguration matched:
      - @ConditionalOnClass found required class 'org.springframework.security.authentication.DefaultAuthenticationEventPublisher' (OnClassCondition)


2021-01-09 21:42:28.413 DEBUG 49828 --- [  restartedMain] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'authenticationFailureListener'

2021-01-09 21:42:28.422 DEBUG 49828 --- [  restartedMain] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'authenticationSuccessListener'

【问题讨论】:

  • 你有没有试过用调试器,一步步看?
  • 如果我没记错的话,这是设计使然,您必须手动连接事件发布者。在这里检查这个答案:stackoverflow.com/a/32995809/294657

标签: java spring-boot spring-security jwt


【解决方案1】:

您需要在安全配置中配置处理程序。

@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final LoginSuccessHandler loginSuccessHandler;
    private final LoginFailureHandler loginFailureHandler;
    ...

    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        http
                .sessionManagement()
                
                ...

                .successHandler(loginSuccessHandler)
                .failureHandler(loginFailureHandler)
  
                ...
    }


你的成功处理器需要实现接口“AuthenticationSuccessHandler”,例如:

@Slf4j
@Component
@RequiredArgsConstructor
public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
 
    private final LoginSuccessRepository loginSuccessRepository;
     
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
            Authentication authentication) throws IOException, ServletException {
 
        // TODO you implementation
         
        super.onAuthenticationSuccess(request, response, authentication);
    }
 
}

你的失败处理器需要实现接口“AuthenticationFailureHandler”,例如:

@Slf4j
@Component
@RequiredArgsConstructor
public class LoginFailureHandler implements AuthenticationFailureHandler {
 

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
 
        // TODO your implementation
    }
}

【讨论】:

    猜你喜欢
    • 2016-02-10
    • 2023-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多