Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/logging/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring安全认证日志_Spring_Logging_Spring Security_Log4j - Fatal编程技术网

Spring安全认证日志

Spring安全认证日志,spring,logging,spring-security,log4j,Spring,Logging,Spring Security,Log4j,我正在使用SpringSecurity3.1对网站的用户进行身份验证。当由于spring security无法连接到数据库而导致登录失败时,我的日志中会出现以下语句: 2012-07-12 11:42:45,419 [ajp-bio-8009-exec-1] DEBUG org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Authentication request

我正在使用SpringSecurity3.1对网站的用户进行身份验证。当由于spring security无法连接到数据库而导致登录失败时,我的日志中会出现以下语句:

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!
我的问题是,为什么这是一个调试语句而不是一个错误?为了找到真正的错误,我不得不费力地阅读大量的调试语句

编辑

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

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

该消息在
AbstractAuthenticationProcessingFilter中打印。身份验证未成功

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
(请参阅我的内联评论):

也许应该在这里记录一个错误-您可以使用Spring记录JIRA以请求该错误。尽管他们可能假设每个人都将提供一个定制的
userdetails服务
,并在那里捕获/记录他们自己的异常。如果您使用的是
JdbcDaoImpl
,则不会。我认为
JdbcDaoImpl
只是一个例子,并不健壮。根据文件:

好消息是我们提供了许多UserDetailsService 实现,包括使用内存映射的实现 (InMemoryDaoImpl)和另一个使用JDBC的(JdbcDaoImpl)。大多数用户 尽管如此,他们倾向于编写自己的实现 只需位于现有数据访问对象(DAO)之上 代表他们的员工、客户或 应用程序

我的解决方案:

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

}
@组件
公共类AuthenticationEventListener实现ApplicationListener{
私有静态记录器=Logger.getLogger(AuthenticationEventListener.class);
@凌驾
ApplicationEvent上的公共无效(AbstractAuthenticationEvent authenticationEvent){
if(InteractiveAuthenticationEvent的authenticationEvent实例InteractiveAuthenticationSuccessEvent){
//忽略以防止使用AuthenticationSuccessEvent重复记录
返回;
}
Authentication=authenticationEvent.getAuthentication();
String auditMessage=“使用用户名进行登录尝试:”+authentication.getName()+“\t\t成功:“+authentication.isAuthenticated()”;
logger.info(auditMessage);
}
}

不需要其他配置。

如何确定我使用的是哪种UserDetailService?能否发布配置的
部分?是的,
JdbcDaoImpl
。因此,如果您想要更好地记录错误,基本上需要编写自己的
UserDetailsService
。好消息是这样做非常容易——您只需要实现一种方法(
loadUserByUsername
)。所以我不得不放弃Spring Security的开箱即用实现的便利性和可靠性,而使用我自己的方法,仅仅是为了更好地记录登录失败?那听起来像是浪费时间。。。更不用说打开引入新bug的大门了。在这种情况下,最好记录数据库连接不正确/数据库关闭等情况。您必须决定什么对您的情况更重要。我建议您查看一下
JdbcDaoImpl
的源代码,看看它是如何工作的?是否必须将其内置到主web应用程序jar文件中?我已使用类似以下内容将记录器与JDBC结合使用:
@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);
   }

}