当前位置: 首页 > 知识库问答 >
问题:

@未激发AuthenticationSuccessEvent或InteractiveAuthenticationSuccessEvent的事件侦听器

卓正业
2023-03-14

我有一个听众在Spring的背景下:

package listeners;

import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.security.authentication.event.AbstractAuthenticationEvent;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
import org.springframework.stereotype.Component;
import services.UserService;
import services.security.CustomUserDetails;

/**
 *
 * @author sergio
 */
@Component
public class AuthenticationSuccessEventHandler{

    private static Logger logger = LoggerFactory.getLogger(AuthenticationSuccessEventHandler.class);

    @Autowired
    private UserService userService;

    @EventListener({AuthenticationSuccessEvent.class, InteractiveAuthenticationSuccessEvent.class})
    public void processAuthenticationSuccessEvent(AbstractAuthenticationEvent  e) {
        logger.info("Autenticación realizada ....");
        // Actualizamos la útltima fecha de acceso
        String username = ((CustomUserDetails) e.getAuthentication().getPrincipal()).getUsername();
        logger.info("Actualizando último acceso para user: " + username);
        userService.updateLastLoginAccess(username, new Date());
    }   
}

根据Spring调试消息,这是在上下文中成功创建的。

DEBUG DefaultListableBeanFactory:448 - Creating instance of bean 'authenticationSuccessEventHandler'
2016-12-11 11:33:29 DEBUG InjectionMetadata:72 - Registered injected element on class [listeners.AuthenticationSuccessEventHandler]: AutowiredFieldElement for private services.UserService listeners.AuthenticationSuccessEventHandler.userService

当我在应用程序中正确身份验证时,Spring Security不会释放任何事件,因此不会调用此事件侦听器。

我的Spring Security配置是这样的

@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = CustomUserDetailsService.class)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

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

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/admin/signup").anonymous()
                .antMatchers("/admin/**").authenticated()
                .anyRequest().permitAll()
                .and()
                .formLogin().loginPage("/admin/login").permitAll()
                .usernameParameter("username").passwordParameter("password")
                .and()
                .logout()
                    .logoutRequestMatcher(new AntPathRequestMatcher("/admin/logout"))
                    .logoutSuccessUrl("/admin/login?logout")
                .and()
                .exceptionHandling().accessDeniedPage("/403")
                .and()
                .csrf();
    }
}

SecurityWebApplicationInitializer

package config;

import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

/**
 *
 * @author sergio
 */
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {

}

我使用的是Spring Security 4.2.0。释放。

共有3个答案

扈昀
2023-03-14

以下是Spring Security文档的解释(在撰写本文时,Spring Security的版本是5.6.1):

要侦听这些事件,您必须首先发布一个AuthenticationEventPublisher。Spring Security的DefaultAuthenticationEventPublisher可能会做得很好:

@Bean
public AuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher appEventPublisher) {
  return new DefaultAuthenticationEventPublisher(appEventPublisher);
}

看见https://docs.spring.io/spring-security/reference/servlet/authentication/events.html

丌官和泰
2023-03-14

我就是这样做到的。

1) 在应用程序类中,公开应用程序侦听器,如

@Bean
public ApplicationListener applicationListener(){
    return new AuthSuccessApplicationListener();
}

2)实现Auth成功应用程序监听器例如

public class AuthSuccessApplicationListener implements 
ApplicationListener<InteractiveAuthenticationSuccessEvent>{

@Autowired(required=false)
HttpSession httpSession;

@Autowired
Environment env;

/**
 * Handle an application event.
 *
 * @param appEvent the event to respond to
 */
@Override
public void onApplicationEvent(InteractiveAuthenticationSuccessEvent appEvent) {

    if (appEvent!=null) {
        LdapUserDetailsImpl ldapUserDetailsImpl = (LdapUserDetailsImpl) appEvent.getAuthentication().getPrincipal();
    try {
            if (ldapUserDetailsImpl != null) {

                logger.info("Session Created for " + ldapUserDetailsImpl.getUsername());

                if (httpSession.getAttribute("adminUser") == null) {
                    // check user is admin and set into session
                    if (isAdminUser(ldapUserDetailsImpl.getUsername())) {
                        httpSession.setAttribute("adminUser", "ADMIN_USER");
                        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
                        List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(auth.getAuthorities());
                        // Add the ROLE_ADMIN into Authorities
                        authorities.add(new SimpleGrantedAuthority(SecurityConfig.ADMIN));
                        // Create a new Authentication based on current principal and authorities and set into Security Context
                        Authentication newAuth = new UsernamePasswordAuthenticationToken(auth.getPrincipal(), auth.getCredentials(), authorities);
                        SecurityContextHolder.getContext().setAuthentication(newAuth);
                    }
                }
            }
        } catch (Exception e) {
            logger.error("Exception occurred : " + e.getMessage());
        }
    }
}
南门志
2023-03-14

您可能需要注册事件发布基础结构(例如,通过配置DefaultAuthenticationEventPublisher)。

@EnableWebSecurity
class SecurityConfig extends WebSecurityConfigurerAdapter {

    ...

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

    @Bean
    public DefaultAuthenticationEventPublisher authenticationEventPublisher() {
        return new DefaultAuthenticationEventPublisher();
    }
}
 类似资料:
  • 我的代码使用jQuery。我有一个密码输入框,我想要得到输入的密码任何时候。 下面是我的代码: 我确信这是一个正确的代码,因为当我在浏览器的控制台中输入它时,它可以工作,但当我重新加载页面时,它就不工作了 我能做什么?

  • 有没有办法防止事件链中的一些听众为事件开火,但允许链上的其他人开火? 比如我有这个结构 假设我已经将单击事件监听器连接到body、div#1和div#2。是否有可能在div#2事件监听器上阻止事件进入div#1或介于两者之间的任何其他监听器,并允许事件在body元素上触发? 我这样说是因为我使用谷歌地图和emberjs构建了一系列可以在地图上显示的交互式信息框。问题是ember将事件侦听器附加到b

  • 我通过infinispan缓存添加了CacheEntryExpired侦听器的n实现。addListener()方法。 侦听器事件在条目过期时激发。问题是,每次事件触发两次。 我验证(使用调试器和cache.getListeners())缓存不包含我的同一个侦听器的两个实例。getListeners的结果是: 所以只有一个听众。侦听器实现接口: 一个实现看起来像: 但是从接口中删除@CacheEn

  • 女士们先生们晚上好, 我有一个Java Swing的问题,我无法解决,也许你可以帮助我。在这里: 我有一个使用BorderLayout的JFrame和许多JPanel 每次我需要设置一个新屏幕(即,从主菜单,当单击搜索按钮时,转到搜索菜单),我只需删除位于中心的组件(JPanel),并将新屏幕(新JPanel)放在中心 这样,我不会在每次我想显示新屏幕时调用所有的页眉和页脚对象 这个系统一切正常,

  • 从元素中移除事件侦听器。 使用 EventTarget.removeEventListener() 从元素中删除一个事件监听器。 省略第四个参数 opts ,则默认使用 false 或者根据添加事件监听器时使用的选项来指定它。 const off = (el, evt, fn, opts = false) => el.removeEventListener(evt, fn, opts); con

  • 问题内容: 我有一个类似的反应成分: 这里,事件列表器已添加到组件。当我刷新页面时,它弹出窗口要求离开页面。 但是当我转到另一个页面并刷新时,它再次显示相同的弹出窗口。 我正在从中删除组件。那为什么不将其删除呢? 如何删除其他页面上的事件? 问题答案: 本应该得到的引用到在分配相同的回调。重新创建该功能将无效。解决方案是在其他地方(在本示例中)创建回调,并将其作为对和的引用传递: 反应钩子 您可以