1

我正在使用 spring.security.version = 3.1.0.RELEASE。我遇到的问题是由于某种原因 AuthenticationFailureCredentialsExpiredEvent 没有被触发。

在调试代码时,我发现 AbstractUserDetailsAuthenticationProvider 确实在控制台中显示“用户帐户凭据已过期”。但我仍然对为什么没有触发相关事件感到困惑。

这是我的代码:

class JpaUserDetails implements UserDetails {
...
...
   @Override
   public boolean isCredentialsNonExpired() {
       if (some logic) {
           return true;
       }
       else {
           return false;
       }
   }
}

我确实看到 AbstractUserDetailsAuthenticationProvider 在控制台中显示“用户帐户凭据已过期”,来自以下弹簧代码行:

public abstract class AbstractUserDetailsAuthenticationProvider implements AuthenticationProvider, InitilizeBean, MessageSourceAware {
...
...
    private class DefaultPostAuthenticationChecks implements UserDetailsChecker {
        public void check(UserDetails user) {
            if(!user.isCredentialsNonExpired()) {
                logger.debug("User account credentials have expired");
                throw new CredentialsExpiredException(message.getMessage(
                          "AbstractUserDetailsAuthenticationProvider.credentialsExpired",
                          "User credentials have expired"), user);
            }
        }
    }
}

问题是,当用户凭据过期时,我希望 Spring 生成事件 AuthenticationFailureCredentialsExpiredEvent,我正在通过以下方式处理该事件:

class SecurityEventDispatcher implements ApplicationListener<ApplicationEvent> {
    final List<SecurityEventListener> listeners = new ArrayList<SecurityEventListener>();

    public void registerListener(SecurityEventListener listener) {
        this.listener.add(listener);
    }

    public void onApplicationEvent(ApplicationEvent event) {
        for (SecurityEventListener listener : this.listeners) {
            if(listener.canHandle(event)) {
                listener.handle(event);
            }
        }
    }
}

这就是我处理登录失败事件的方式:

public class LoginFailedEvent extends SecurityEventListener {

    @Override
    public boolean canHandle(Object event) {
        if(event instanceof AbstractAuthenticationFailureEvent) {
            return true;
        }
        else {
            return false;
        }
    }

    @Override
    public void handle(Object event) {
        if (event instanceof AuthenticationFailureBadCredentialsEvent) {
            // do something
        }

        if (event instanceof AuthenticationFailureCredentialsExpiredEvent) {
            // do something
        }
    }
}

我之前提到的问题是 AuthenticationFailureCredentialsExpiredEvent 永远不会被触发。我已经测试了 AuthenticationFailureBadCredentialsEvent 工作正常。

这是我因凭据错误而得到的结果:(工作正常)

org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent

这是我在密码过期的情况下得到的:

ServletRequestHandledEvent: url=[/app/loginFailure] with failureCause = null

有谁知道可能出了什么问题?任何帮助将不胜感激。

4

2 回答 2

1

这是这个问题的答案,因为没有太多关于这个问题的文献。

您可能需要将 ProviderManager 的 ('s) eventPublisher 设置为 NullEventPublisher 以外的其他内容。没有一种简单的方法可以通过标签做到这一点,因此您需要使用标准 bean 配置创建 AuthenticationProvider 并将其注入到 ProviderManager 的标准 Spring Bean 中。

Rob Winch - 弹簧安全主管

于 2013-02-14T22:52:05.427 回答
1

如果有人遇到这个问题,只需将 spring security 升级到 3.1.2 或+,问题就解决了。

于 2013-05-21T21:05:42.217 回答