我正在使用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语句而不是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>
答案 0 :(得分: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);
}
}
无需其他配置。
答案 1 :(得分: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());
身份验证可能有多种失败方式,包括基于用户输入。例如,在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);
}
也许应该在这里记录一个错误 - 你可以用Spring记录一个JIRA来请求它。虽然也许他们假设每个人都要提供自定义UserDetailsService
并且会在那里捕获/记录他们自己的例外。如果您使用JdbcDaoImpl
,则不会。我认为JdbcDaoImpl
旨在成为一个例子并且不健全。根据文档:
好消息是我们提供了许多UserDetailsService 实现,包括使用内存映射的实现 (InMemoryDaoImpl)和另一个使用JDBC(JdbcDaoImpl)。大多数用户 但是,他们往往会通过他们的实现来编写自己的实现 只是坐在现有的数据访问对象(DAO)之上 代表他们的员工,客户或其他用户 应用