2012-07-12 97 views
4

我正在使用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! 

我的问题是,为什么这是一个DEBUG语句,而不是一个错误?我必须通过大量的调试语句来查找实际的错误。

编辑

这里是我的认证管理器:

<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> 

回答

7

这消息在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()); 

有多种方式的认证可能会失败,包括基于在用户输入。例如,在AbstractUserDetailsAuthenticationProvider.authenticate,一个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; 
      } 
     } 

由于可能有正当理由的验证可能会失败,它不会为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); 
    } 

也许一个错误应该被记录在这里 - 你可以记录一个JIRA与Spring来请求。虽然也许他们假设每个人都会提供一个自定义UserDetailsService,并且会在那里记录/记录他们自己的例外情况。如果您使用的是JdbcDaoImpl,则不会。我认为JdbcDaoImpl只是一个例子,并不健全。每文档:

的好消息是,我们提供了好几个UserDetailsS​​ervice 实现,其中一个使用内存映射 (InMemoryDaoImpl),另一个使用JDBC(JdbcDaoImpl)之一。然而,大多数用户 倾向于编写他们自己的,而他们的实现通常仅仅是在 应用程序代表其雇员,客户或其他用户的现有数据访问对象(DAO)之上。

+0

如何找出我正在使用的UserDetailService类型? – 2012-07-13 13:25:06

+0

你可以发布你的配置的''部分吗? – sourcedelica 2012-07-13 15:09:31

+0

问题已更新。 – 2012-07-13 15:25:15

13

我的解决办法:

@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); 
    } 

} 

没有其他配置是必需的。

+0

你在配置中添加AuthenticationEventListener的位置?它是否必须构建到主Web应用程序jar文件中? – whatnick 2015-01-21 04:32:24

+1

我已成功使用这样的使用记录仪使用JDBC: 的 \t <属性名= “数据源”> \t \t \t whatnick 2015-01-22 05:20:14