由于K. Potgieter's implementation,我的Spring应用程序中已经有了一个身份验证过滤器。但是,到目前为止,过滤器仅使用不连接到任何数据库但只返回硬编码值的存储库。我现在正试图从数据库中获取用户详细信息(名称和API密钥)。
问题是,每当我从服务类自动装配存储库时,autowire就会失败。我依赖Spring-data-REST的存储库,因为我希望将来还能从REST API中公开用户详细信息:
@RepositoryRestResource(collectionResourceRel = "users", path = "users")
public interface UserSecurityRepository extends CrudRepository<Users, Long> {
public Users findByUsername(@Param("uname") String name);
public Users findByApiKey(@Param("key") String apiKey);
}
来自身份验证提供程序的我称之为服务:
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
public class RESTDaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
@Override
protected UserDetails retrieveUser(String apiKey, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
UserDetails loadedUser;
try {
loadedUser = this.getUserSecurityService().loadUserByApiKey(apiKey);
} catch (UsernameNotFoundException | UserNotFoundException notFound) {
throw notFound;
} catch (Exception repositoryProblem) {
throw new AuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);
}
if (loadedUser == null) {
throw new AuthenticationServiceException(
"UserSecurityServiceImpl returned null, which is an interface contract violation");
}
return loadedUser;
}
然后,服务调用存储库(上面粘贴的代码)以通过数据库中的API密钥获取用户:
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UserDetails;
@Service
@Transactional
public class UserSecurityServiceImpl extends UserDetailsService {
@Autowired
private UserSecurityRepository userSecurityRepository;
@Override
public UserDetails loadUserByApiKey(String apiKey) throws UserNotFoundException {
UserDetails userDetails = buildUserDetails(userSecurityRepository.findByApiKey(apiKey));
if (userDetails == null) {
throw new UserNotFoundException("User could not be found with the supplied api key.");
}
return userDetails;
}
但是,此提取失败,因为来自服务类的存储库的自动装配失败。我收到这个错误:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userSecurityServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private mypackage.dal.UserSecurityRepository mypackage.services.UserSecurityServiceImpl.userSecurityRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [mypackage.dal.UserSecurityRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) ~[spring-beans-4.1.6.RELEASE.jar:4.1.6.RELEASE]
...
我不会使用Session对象访问数据库,因为我希望我的应用程序是无状态的,并且我在security.xml sec中声明:session-management session-fixation-protection =&#34; none&#34 ; 如你所见:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.0.xsd">
<sec:http disable-url-rewriting="true" entry-point-ref="forbiddenEntryPoint" use-expressions="true" create-session="never">
<sec:anonymous enabled="false"/>
<sec:session-management session-fixation-protection="none"/>
<sec:custom-filter ref="restAuthenticationFilter" position="FORM_LOGIN_FILTER"/>
<sec:intercept-url pattern="/**" access="isFullyAuthenticated()"/>
</sec:http>
<bean id="forbiddenEntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"/>
<sec:authentication-manager alias="defaultAuthenticationManager" erase-credentials="true">
<sec:authentication-provider ref="daoAuthenticationProvider"/>
</sec:authentication-manager>
<bean id="daoAuthenticationProvider" class="mypackage.dal.security.RESTDaoAuthenticationProvider">
<property name="userSecurityService" ref="userSecurityServiceImpl"/>
<property name="passwordEncoder" ref="passwordEncoder"/>
</bean>
<bean id="passwordEncoder" class="mypackagedal.security.authentication.HMacShaPasswordEncoder">
<constructor-arg name="strength" value="256"/>
<constructor-arg name="encodeHashAsBase64" value="true"/>
</bean>
<bean id="restAuthenticationFilter" class="mypackage.dal.security.RESTAuthenticationFilter">
<constructor-arg name="defaultFilterProcessesUrl" value="/"/>
<property name="authenticationManager" ref="defaultAuthenticationManager"/>
<property name="authenticationSuccessHandler">
<!-- Upon successful authentication, Spring will attempt to try and move you to another URL -->
<!-- We have to prevent this because the request for the resource and the authentication all get done in the same request! -->
<bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler">
<property name="redirectStrategy">
<bean class="mypackage.dal.security.NoRedirectStrategy"/>
</property>
</bean>
</property>
</bean>
</beans>
那么,如何使用Repository and Service从数据库中获取这些用户数据而没有会话对象呢?
非常感谢能帮助我的人。
P.S。 我使用的是Hibernate,Liquibase和Hsqldb。我的申请背景如下:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
<context:component-scan base-package="mypackage" />
<context:annotation-config />
<tx:annotation-driven transaction-manager="transactionManager" />
<aop:config proxy-target-class="true" />
<!--<mvc:annotation-driven/>-->
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="suffix" value=".jsp"/>
<property name="prefix" value="/WEB-INF/views/"/>
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
</bean>
<import resource="security-context.xml"/>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="org.hsqldb.jdbc.JDBCDriver" />
<property name="url" value="jdbc:hsqldb:hsql://localhost/sdrdb" />
<property name="username" value="SA" />
<property name="password" value="" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<!-- <bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"
depends-on="flywayAutomaticMigrationBean">-->
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="mypackage.dal.entities" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.connection.pool_size">10</prop>
<prop key="hibernate.connection.show_sql">true</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- <bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean> -->
</beans>
ATTEMPT 2: 这次我试图不再使用RestRepository而是使用Spring Data JPA。但是,在注入依赖项时,我仍然会收到NoSuchBeanDefinitionException。现在我的存储库如下:
@Repository
public class JpaUserSecurityRepositoryImpl {
@PersistenceContext
private EntityManager em;
public Users findByUsername(String name) {
Query query = this.em.createQuery("SELECT users FROM Users WHERE name =:name");
query.setParameter("name", name);
return (Users) query.getSingleResult();
}
public Users findByApiKey(String apiKey) {
Query query = this.em.createQuery("SELECT users FROM Users WHERE api_key =:key");
query.setParameter("key", apiKey);
return (Users) query.getSingleResult();
}
}
我的@Service访问存储库,如下所示:
@Service
public class UserSecurityServiceImpl implements UserSecurityService {
private UserSecurityRepository repository;
@Autowired
public UserSecurityServiceImpl(UserSecurityRepository repository){
this.repository = repository;
}
我收到NoSuchBeanDefinitionException错误:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaUserSecurityRepositoryImpl': Injection of persistence dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.postProcessPropertyValues(PersistenceAnnotationBeanPostProcessor.java:357) ~[spring-orm-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1210) ~[spring-beans-4.1.6.RELEASE.jar:4.1.6.RELEASE]
尝试3:
这次我放弃了没有创建会话的愿望,所以我尝试使用存储库中的SessionFactory。我在security.xml中注释掉了
的行<!--<sec:session-management session-fixation-protection="none"/>-->
从我的服务我访问以下自动装配的存储库(autowire工作):
@Repository
public class DataProviderImpl {
@Autowired
private SessionFactory sessionFactory;
@Transactional
public List<Users> getUsers() {
Session session = sessionFactory.openSession();
//I also tried: Session session = sessionFactory.getCurrentSession();
Query query = session.createQuery("from Users u");
return query.list();
}
public Users findByUsername(String name) {
List<Users> allusers = getUsers();
for (Users user : allusers) {
if (user.getFirstName().equals(name)) {
return user;
}
}
return null;
}
请注意 会话会话= sessionFactory.openSession(); //我也尝试过:Session session = sessionFactory.getCurrentSession(); 从上面的代码。
它编译和部署但是当我打开一个页面,而不是然后获得身份验证失败:错误的密钥等我得到身份验证失败:当我尝试sessionFactory.openConnection()时无法打开连接 我得到了 身份验证失败:没有Hibernate会话绑定到线程,并且配置不允许在此处创建非事务性 当我尝试Session session = sessionFactory.getCurrentSession();来自存储库。
我真的很想设法以某种方式从我的数据库中获取这些数据。任何帮助都将受到超级赞赏!万分感谢
答案 0 :(得分:1)
根据您的第一次尝试,default-spring-context.xml
的内容是什么?组件扫描是否包含您的包装?我原本认为@RepositoryRestResource
声明会让你可以使用这个bean,但我之前没有使用过spring-data-REST,所以我不确定。