我一直在尝试实现Spring Security JDBC身份验证。当我使用JdbcDaoImpl时,它对我有用:
@Bean
public UserDetailsService userDetailsService() {
JdbcDaoImpl jdbcImpl = new JdbcDaoImpl();
jdbcImpl.setDataSource(dataSource());
jdbcImpl.setUsersByUsernameQuery("select username, password, enabled from admin_user where username=?");
jdbcImpl.setAuthoritiesByUsernameQuery(
"select admin_user.username, admin_roles.role from admin_user "
+ "INNER JOIN admin_user_roles ON admin_user.user_id = admin_user_roles.user_id "
+ "INNER JOIN admin_roles ON admin_roles.role_id = admin_user_roles.role_id "
+ "where username=?");
return jdbcImpl;
}
但是,当我切换到使用自定义UserDetailsService来使用.loadUserByUsername(字符串用户名)进行身份验证时,它仍然在我找不到用户的身份验证错误。
我的实施:
在Custom UserDetailsService中:
@Service
public class AdminUserDetailsService implements UserDetailsService {
@Autowired
private AdminUserRepository adminUserRepository;
/* (non-Javadoc)
* @see com.asap.services.AdminUserDetailsService#loadUserByUsername(java.lang.String)
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
try {
AdminUser adminUser = adminUserRepository.findByUsername(username);
Set<GrantedAuthority> authorities = adminUserRepository.getAuthorities(username);
if (adminUser == null) {
return null;
}
return new User(adminUser.getUsername(), adminUser.getPassword(), true, true, true, true, authorities);
} catch (Exception e) {
throw new UsernameNotFoundException("User not found!");
}
}
}
在AdminUserRepository中:
@Repository
@Transactional
public class AdminUserRepositoryImpl implements AdminUserRepository {
@Autowired
private SessionFactory sessionFactory;
@Override
public AdminUser findByUsername(String username) {
try {
AdminUser user = (AdminUser) sessionFactory.getCurrentSession()
.createQuery("FROM AdminUser adminUser " +
"WHERE adminUser.username=:username")
.setParameter("username", username);
System.out.println("findByUsername method user: " + user);
return user;
} catch (HibernateException e) {
System.out.println("findByUsername method in AdminUser throws hibernate exception: " + e.getMessage());
return null;
}
}
@Override
@SuppressWarnings("unchecked")
public Set<GrantedAuthority> getAuthorities(String username) {
Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
List<ViewRole> results = new ArrayList<ViewRole>();
try {
results = sessionFactory.getCurrentSession()
.createQuery("FROM ViewRole viewRole " +
"WHERE viewRole.username=:username")
.setParameter("username", username)
.list();
} catch (HibernateException e) {
System.out.println("getAuthorities method in AdminUser throws hibernate exception: " + e.getMessage());
return null;
}
for (ViewRole viewRole : results) {
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(viewRole.getRole());
authorities.add(grantedAuthority);
}
System.out.println("User Authorities: " + authorities);
return authorities;
}
}
在SecurityConfig中:
@Configuration
@EnableWebSecurity
@ComponentScan("com.asap")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
AdminUserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// Spring Security http filters
http
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/mydesk")
.failureUrl("/login?error")
.permitAll()
.and()
.logout()
.permitAll()
.and()
.requiresChannel() // HTTPS Channel Security enabled
.anyRequest()
.requiresSecure();
}
@Override
public void configure(WebSecurity web) throws Exception {
// Spring Security web filters
web
.ignoring()
.antMatchers("/resources/**");
}
}
这是控制台日志:
16:44:11.377 [https-jsse-nio-8443-exec-11] DEBUG org.springframework.security.web.access.ExceptionTranslationFilter - Chain processed normally
16:44:11.377 [https-jsse-nio-8443-exec-11] DEBUG org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
16:44:15.538 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/login'; against '/resources/**'
16:44:15.538 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.security.web.FilterChainProxy - /login at position 1 of 13 in additional filter chain; firing Filter: 'ChannelProcessingFilter'
16:44:15.538 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.security.web.access.channel.ChannelProcessingFilter - Request: FilterInvocation: URL: /login; ConfigAttributes: [REQUIRES_SECURE_CHANNEL]
16:44:15.538 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.security.web.FilterChainProxy - /login at position 2 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
16:44:15.538 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.security.web.FilterChainProxy - /login at position 3 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
16:44:15.538 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.security.web.context.HttpSessionSecurityContextRepository - HttpSession returned null object for SPRING_SECURITY_CONTEXT
16:44:15.538 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.security.web.context.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@1e4ab2e2. A new one will be created.
16:44:15.538 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.security.web.FilterChainProxy - /login at position 4 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
16:44:15.538 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.security.web.FilterChainProxy - /login at position 5 of 13 in additional filter chain; firing Filter: 'CsrfFilter'
16:44:15.539 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.security.web.FilterChainProxy - /login at position 6 of 13 in additional filter chain; firing Filter: 'LogoutFilter'
16:44:15.539 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/login'; against '/logout'
16:44:15.539 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.security.web.FilterChainProxy - /login at position 7 of 13 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
16:44:15.539 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/login'; against '/login'
16:44:15.539 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Request is to process authentication
16:44:15.543 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.security.authentication.ProviderManager - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
16:44:15.553 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.transaction.annotation.AnnotationTransactionAttributeSource - Adding transactional method 'com.asap.repositories.AdminUserRepositoryImpl.findByUsername' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
16:44:15.564 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'transactionManager'
16:44:15.573 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.orm.hibernate5.HibernateTransactionManager - Creating new transaction with name [com.asap.repositories.AdminUserRepositoryImpl.findByUsername]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
16:44:15.573 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.orm.hibernate5.HibernateTransactionManager - Opened new Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] for Hibernate transaction
16:44:15.574 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.orm.hibernate5.HibernateTransactionManager - Preparing JDBC Connection of Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])]
16:44:15.574 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.jdbc.datasource.DriverManagerDataSource - Creating new JDBC DriverManager Connection to [jdbc:sqlserver://localhost:1433;databaseName=ASAP_DEV]
16:44:15.803 [https-jsse-nio-8443-exec-3] DEBUG org.hibernate.engine.transaction.internal.TransactionImpl - begin
16:44:15.810 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.orm.hibernate5.HibernateTransactionManager - Exposing Hibernate transaction as JDBC transaction [ConnectionID:3 ClientConnectionId: 478cbaa9-c943-4a39-a0df-44e35aa02f8d]
16:44:15.841 [https-jsse-nio-8443-exec-3] DEBUG org.hibernate.hql.internal.QueryTranslatorFactoryInitiator - QueryTranslatorFactory : org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory@71b49fda
16:44:15.842 [https-jsse-nio-8443-exec-3] INFO org.hibernate.hql.internal.QueryTranslatorFactoryInitiator - HHH000397: Using ASTQueryTranslatorFactory
16:44:15.891 [https-jsse-nio-8443-exec-3] DEBUG org.hibernate.hql.internal.ast.QueryTranslatorImpl - parse() - HQL: FROM com.asap.models.AdminUser adminUser WHERE adminUser.username=:username
16:44:15.904 [https-jsse-nio-8443-exec-3] DEBUG org.hibernate.hql.internal.ast.QueryTranslatorImpl - --- HQL AST ---
\-[QUERY] Node: 'query'
+-[SELECT_FROM] Node: 'SELECT_FROM'
| \-[FROM] Node: 'FROM'
| \-[RANGE] Node: 'RANGE'
| +-[DOT] Node: '.'
| | +-[DOT] Node: '.'
| | | +-[DOT] Node: '.'
| | | | +-[IDENT] Node: 'com'
| | | | \-[IDENT] Node: 'asap'
| | | \-[IDENT] Node: 'models'
| | \-[IDENT] Node: 'AdminUser'
| \-[ALIAS] Node: 'adminUser'
\-[WHERE] Node: 'WHERE'
\-[EQ] Node: '='
+-[DOT] Node: '.'
| +-[IDENT] Node: 'adminUser'
| \-[IDENT] Node: 'username'
\-[COLON] Node: ':'
\-[IDENT] Node: 'username'
16:44:15.904 [https-jsse-nio-8443-exec-3] DEBUG org.hibernate.hql.internal.ast.ErrorCounter - throwQueryException() : no errors
16:44:15.980 [https-jsse-nio-8443-exec-3] DEBUG org.hibernate.hql.internal.antlr.HqlSqlBaseWalker - select << begin [level=1, statement=select]
16:44:16.024 [https-jsse-nio-8443-exec-3] DEBUG org.hibernate.hql.internal.ast.tree.FromElement - FromClause{level=1} : com.asap.models.AdminUser (adminUser) -> adminuser0_
16:44:16.029 [https-jsse-nio-8443-exec-3] DEBUG org.hibernate.hql.internal.ast.tree.FromReferenceNode - Resolved : adminUser -> adminuser0_.user_id
16:44:16.031 [https-jsse-nio-8443-exec-3] DEBUG org.hibernate.hql.internal.ast.tree.DotNode - getDataType() : username -> org.hibernate.type.StringType@6448679f
16:44:16.033 [https-jsse-nio-8443-exec-3] DEBUG org.hibernate.hql.internal.ast.tree.FromReferenceNode - Resolved : adminUser.username -> adminuser0_.username
16:44:16.038 [https-jsse-nio-8443-exec-3] DEBUG org.hibernate.hql.internal.antlr.HqlSqlBaseWalker - select : finishing up [level=1, statement=select]
16:44:16.038 [https-jsse-nio-8443-exec-3] DEBUG org.hibernate.hql.internal.ast.HqlSqlWalker - processQuery() : ( SELECT ( FromClause{level=1} dbo.admin_user adminuser0_ ) ( WHERE ( = ( adminuser0_.username adminuser0_.user_id username ) ? ) ) )
16:44:16.048 [https-jsse-nio-8443-exec-3] DEBUG org.hibernate.hql.internal.ast.HqlSqlWalker - Derived SELECT clause created.
16:44:16.058 [https-jsse-nio-8443-exec-3] DEBUG org.hibernate.hql.internal.ast.util.JoinProcessor - Using FROM fragment [dbo.admin_user adminuser0_]
16:44:16.058 [https-jsse-nio-8443-exec-3] DEBUG org.hibernate.hql.internal.antlr.HqlSqlBaseWalker - select >> end [level=1, statement=select]
16:44:16.059 [https-jsse-nio-8443-exec-3] DEBUG org.hibernate.hql.internal.ast.QueryTranslatorImpl - --- SQL AST ---
\-[SELECT] QueryNode: 'SELECT' querySpaces (dbo.admin_user)
+-[SELECT_CLAUSE] SelectClause: '{derived select clause}'
| +-[SELECT_EXPR] SelectExpressionImpl: 'adminuser0_.user_id as user_id1_5_' {FromElement{explicit,not a collection join,not a fetch join,fetch non-lazy properties,classAlias=adminUser,role=null,tableName=dbo.admin_user,tableAlias=adminuser0_,origin=null,columns={,className=com.asap.models.AdminUser}}}
| \-[SQL_TOKEN] SqlFragment: 'adminuser0_.add_date as add_date2_5_, adminuser0_.add_user_id as add_user3_5_, adminuser0_.group_id as group_i13_5_, adminuser0_.description as descript4_5_, adminuser0_.enabled as enabled5_5_, adminuser0_.first_name as first_na6_5_, adminuser0_.last_name as last_nam7_5_, adminuser0_.middle_name as middle_n8_5_, adminuser0_.password as password9_5_, adminuser0_.update_date as update_10_5_, adminuser0_.update_user_id as update_11_5_, adminuser0_.username as usernam12_5_'
+-[FROM] FromClause: 'FROM' FromClause{level=1, fromElementCounter=1, fromElements=1, fromElementByClassAlias=[adminUser], fromElementByTableAlias=[adminuser0_], fromElementsByPath=[], collectionJoinFromElementsByPath=[], impliedElements=[]}
| \-[FROM_FRAGMENT] FromElement: 'dbo.admin_user adminuser0_' FromElement{explicit,not a collection join,not a fetch join,fetch non-lazy properties,classAlias=adminUser,role=null,tableName=dbo.admin_user,tableAlias=adminuser0_,origin=null,columns={,className=com.asap.models.AdminUser}}
\-[WHERE] SqlNode: 'WHERE'
\-[EQ] BinaryLogicOperatorNode: '='
+-[DOT] DotNode: 'adminuser0_.username' {propertyName=username,dereferenceType=PRIMITIVE,getPropertyPath=username,path=adminUser.username,tableAlias=adminuser0_,className=com.asap.models.AdminUser,classAlias=adminUser}
| +-[ALIAS_REF] IdentNode: 'adminuser0_.user_id' {alias=adminUser, className=com.asap.models.AdminUser, tableAlias=adminuser0_}
| \-[IDENT] IdentNode: 'username' {originalText=username}
\-[NAMED_PARAM] ParameterNode: '?' {name=username, expectedType=org.hibernate.type.StringType@6448679f}
16:44:16.059 [https-jsse-nio-8443-exec-3] DEBUG org.hibernate.hql.internal.ast.ErrorCounter - throwQueryException() : no errors
16:44:16.072 [https-jsse-nio-8443-exec-3] DEBUG org.hibernate.hql.internal.ast.QueryTranslatorImpl - HQL: FROM com.asap.models.AdminUser adminUser WHERE adminUser.username=:username
16:44:16.072 [https-jsse-nio-8443-exec-3] DEBUG org.hibernate.hql.internal.ast.QueryTranslatorImpl - SQL: select adminuser0_.user_id as user_id1_5_, adminuser0_.add_date as add_date2_5_, adminuser0_.add_user_id as add_user3_5_, adminuser0_.group_id as group_i13_5_, adminuser0_.description as descript4_5_, adminuser0_.enabled as enabled5_5_, adminuser0_.first_name as first_na6_5_, adminuser0_.last_name as last_nam7_5_, adminuser0_.middle_name as middle_n8_5_, adminuser0_.password as password9_5_, adminuser0_.update_date as update_10_5_, adminuser0_.update_user_id as update_11_5_, adminuser0_.username as usernam12_5_ from dbo.admin_user adminuser0_ where adminuser0_.username=?
16:44:16.072 [https-jsse-nio-8443-exec-3] DEBUG org.hibernate.hql.internal.ast.ErrorCounter - throwQueryException() : no errors
16:44:16.124 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.orm.hibernate5.HibernateTransactionManager - Initiating transaction rollback
16:44:16.128 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.orm.hibernate5.HibernateTransactionManager - Rolling back Hibernate transaction on Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])]
16:44:16.150 [https-jsse-nio-8443-exec-3] DEBUG org.hibernate.engine.transaction.internal.TransactionImpl - rolling back
16:44:16.162 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.orm.hibernate5.HibernateTransactionManager - Closing Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] after transaction
16:44:16.278 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.security.authentication.dao.DaoAuthenticationProvider - User 'A.Montano.ASAP' not found
16:44:16.279 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'delegatingApplicationListener'
16:44:16.279 [https-jsse-nio-8443-exec-3] DEBUG org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials
我使用STS调试器来跟踪。显然,Spring安全性使用用户名和密码输入并编码密码,但不知何故无法从DB获取用户(它甚至没有进入存储库调用)。