Spring Security身份验证日志记录

Bry*_*son 4 logging spring log4j spring-security

我正在使用Spring Security 3.1来验证网站的用户.当登录失败,因为spring安全性无法连接到数据库时,我在日志中收到以下语句:

2012-07-12 11:42:45,419 [ajp-bio-8009-exec-1] DEBUG      org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Authentication request failed: org.springframework.security.authentication.AuthenticationServiceException: Could not get JDBC Connection; nested exception is java.sql.SQLException: Connections could not be acquired from the underlying database!
Run Code Online (Sandbox Code Playgroud)

我的问题是,为什么这是一个DEBUG语句而不是ERROR?我必须浏览大量的调试语句才能找到实际的错误.

编辑

这是我的身份验证管理器:

<bean id="securityDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="java:comp/env/securityDS"/>
    <property name="resourceRef" value="true"/>
</bean>

<bean id="encoder" class="org.springframework.security.crypto.password.StandardPasswordEncoder" />

<security:authentication-manager>
    <security:authentication-provider>
        <security:password-encoder ref="encoder" />
        <security:jdbc-user-service 
            data-source-ref="securityDataSource"
            authorities-by-username-query="SELECT username, authority FROM login WHERE username = ?"
            users-by-username-query="SELECT username, password, enabled FROM login WHERE username = ?"
        />        
    </security:authentication-provider>
</security:authentication-manager>
Run Code Online (Sandbox Code Playgroud)

Alo*_*onL 14

我的解决方案

@Component
public class AuthenticationEventListener implements ApplicationListener<AbstractAuthenticationEvent> {

   private static Logger logger = Logger.getLogger(AuthenticationEventListener.class);

   @Override
   public void onApplicationEvent(AbstractAuthenticationEvent authenticationEvent) {
      if (authenticationEvent instanceof InteractiveAuthenticationSuccessEvent) {
         // ignores to prevent duplicate logging with AuthenticationSuccessEvent
         return;
      }
      Authentication authentication = authenticationEvent.getAuthentication();
      String auditMessage = "Login attempt with username: " + authentication.getName() + "\t\tSuccess: " + authentication.isAuthenticated();
      logger.info(auditMessage);
   }

}
Run Code Online (Sandbox Code Playgroud)

无需其他配置.


sou*_*ica 8

该消息打印在AbstractAuthenticationProcessingFilter.unsuccessfulAuthentication:

protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
        AuthenticationException failed) throws IOException, ServletException {
    SecurityContextHolder.clearContext();

    if (logger.isDebugEnabled()) {
        logger.debug("Authentication request failed: " + failed.toString());
Run Code Online (Sandbox Code Playgroud)

身份验证可能有多种失败方式,包括基于用户输入.例如,如果找不到用户名,则可能抛出AbstractUserDetailsAuthenticationProvider.authenticatea BadCredentialsException:

        try {
            user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
        } catch (UsernameNotFoundException notFound) {
            logger.debug("User '" + username + "' not found");

            if (hideUserNotFoundExceptions) {
                throw new BadCredentialsException(messages.getMessage(
                        "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
            } else {
                throw notFound;
            }
        }
Run Code Online (Sandbox Code Playgroud)

由于可能存在合法的原因导致身份验证失败,因此AbstractAuthenticationProcessingFilter记录错误没有意义.如果存在系统错误,则应该在下游进一步记录错误.

我怀疑问题出在了DaoAuthenticationProvider(请参阅我的评论内联):

protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
        throws AuthenticationException {
    UserDetails loadedUser;

    try {
        loadedUser = this.getUserDetailsService().loadUserByUsername(username);
    }
    catch (DataAccessException repositoryProblem) {
        // *** ERROR SHOULD BE LOGGED HERE ***
        throw new AuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);
    }
Run Code Online (Sandbox Code Playgroud)

也许这里应该记录一个错误 - 你可以用Spring记录一个JIRA来请求它.虽然也许他们假设每个人都会提供一个自定义,UserDetailsService并会在那里捕获/记录他们自己的例外.如果你使用JdbcDaoImpl它没有.我认为这JdbcDaoImpl是一个例子而且不健全.根据文档:

好消息是我们提供了许多UserDetailsS​​ervice实现,包括一个使用内存映射(InMemoryDaoImpl)和另一个使用JDBC(JdbcDaoImpl)的实现.但是,大多数用户倾向于自己编写,他们的实现通常只是位于代表其员工,客户或应用程序其他用户的现有数据访问对象(DAO)之上.