Spring BadCredentials 事件未触发
Spring BadCredentials Event not firing
如果用户尝试使用错误的凭据进行身份验证,我想记录。因此,我已将此事件侦听器 class 添加到我的项目中:
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 安全默认登录页面。使用错误的凭据时页面显示 "bad credentials" 错误,但我上面的方法没有被调用。
我有非常相似的成功事件侦听器代码,效果非常好:
@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 安全 Java 配置:
@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();
}
}
我不知道这里发生了什么,非常感谢帮助!
Spring版本:4.0.9
Spring安全版本:3.2.5(也试过4.0.1)
编辑:
好的,我将 Spring 的日志级别设置为 DEBUG,但什么也没有。我搜索了 "Listener" 的每一次出现,日志指出 AuthenticationFailureListener 和 AuthenticationSuccessListeners 的实例已创建且没有任何错误。
我什至将日志放入 diff 工具(在替换所有时间和审查之后)并与 FailureListener 代码被注释掉的代码版本进行比较,但没有找到任何东西。有需要的可以自行搜索:
https://www.diffchecker.com/cwdn4sp4
在页面底部,您会在左侧找到纯日志文本。
Edit2:部分解决
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);
}
即设计。
AbstractAuthenticationProcessingFilter
的 Javadoc 对此很清楚:
活动发布:
如果身份验证成功,将通过应用程序上下文发布 InteractiveAuthenticationSuccessEvent。 如果身份验证不成功,将不会发布任何事件,因为这通常会通过特定于 AuthenticationManager 的应用程序事件进行记录。
(强调我的)
如果您想明确发送身份验证失败的事件,您可以使用自定义 AuthenticationFailureHandler
扩展 SimpleUrlAuthenticationFailureHandler
发送事件并调用 base class 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
希望对您有所帮助。
源代码LoggerListener works fine with Spring Security 3.2.8. See Grepcode。
您的授权代码:
@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!");
}
}
}
如果用户尝试使用错误的凭据进行身份验证,我想记录。因此,我已将此事件侦听器 class 添加到我的项目中:
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 安全默认登录页面。使用错误的凭据时页面显示 "bad credentials" 错误,但我上面的方法没有被调用。 我有非常相似的成功事件侦听器代码,效果非常好:
@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 安全 Java 配置:
@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();
}
}
我不知道这里发生了什么,非常感谢帮助!
Spring版本:4.0.9
Spring安全版本:3.2.5(也试过4.0.1)
编辑:
好的,我将 Spring 的日志级别设置为 DEBUG,但什么也没有。我搜索了 "Listener" 的每一次出现,日志指出 AuthenticationFailureListener 和 AuthenticationSuccessListeners 的实例已创建且没有任何错误。
我什至将日志放入 diff 工具(在替换所有时间和审查之后)并与 FailureListener 代码被注释掉的代码版本进行比较,但没有找到任何东西。有需要的可以自行搜索:
https://www.diffchecker.com/cwdn4sp4
在页面底部,您会在左侧找到纯日志文本。
Edit2:部分解决
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);
}
即设计。
AbstractAuthenticationProcessingFilter
的 Javadoc 对此很清楚:
活动发布:
如果身份验证成功,将通过应用程序上下文发布 InteractiveAuthenticationSuccessEvent。 如果身份验证不成功,将不会发布任何事件,因为这通常会通过特定于 AuthenticationManager 的应用程序事件进行记录。
(强调我的)
如果您想明确发送身份验证失败的事件,您可以使用自定义 AuthenticationFailureHandler
扩展 SimpleUrlAuthenticationFailureHandler
发送事件并调用 base class 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
希望对您有所帮助。
源代码LoggerListener works fine with Spring Security 3.2.8. See Grepcode。
您的授权代码:
@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!");
}
}
}