通过Spring存储库和服务从数据库中获取,无需会话

通过Spring存储库和服务从数据库中获取,无需会话,spring,spring-mvc,spring-security,spring-data-jpa,restful-authentication,Spring,Spring Mvc,Spring Security,Spring Data Jpa,Restful Authentication,我在spring应用程序中使用了一个身份验证过滤器,这要归功于。但是,到目前为止,过滤器只使用一个存储库,该存储库不连接到任何数据库,只返回硬编码的值。我现在正试图从数据库中获取用户详细信息(名称和api密钥) 问题是,每当我从服务类自动连接存储库时,自动连接都会失败。我拥有的存储库依赖于Spring data REST,因为我希望将来还可以从REST API公开用户详细信息: @RepositoryRestResource(collectionResourceRel = "users", pa

我在spring应用程序中使用了一个身份验证过滤器,这要归功于。但是,到目前为止,过滤器只使用一个存储库,该存储库不连接到任何数据库,只返回硬编码的值。我现在正试图从数据库中获取用户详细信息(名称和api密钥)

问题是,每当我从服务类自动连接存储库时,自动连接都会失败。我拥有的存储库依赖于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);    
}
然后,服务调用存储库(上面粘贴的代码),通过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]
...
我不会使用会话对象访问数据库,因为我希望我的应用程序是无状态的,并且我在security.xml sec:Session management Session-protection=“none”中声明,如您所见:

<?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>
my@Service访问存储库的方式如下:

@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
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"/>-->

通过我的服务,我可以访问以下autowired存储库(autowire工作):

@存储库
公共类DataProviderImpl{
@自动连线
私人会话工厂会话工厂;
@交易的
公共列表getUsers(){
Session Session=sessionFactory.openSession();
//我还尝试了:Session Session=sessionFactory.getCurrentSession();
Query Query=session.createQuery(“来自用户u”);
返回query.list();
}
公共用户findByUsername(字符串名称){
List alluser=getUsers();
用于(用户:allusers){
if(user.getFirstName().equals(name)){
返回用户;
}
}
返回null;
}
请注意 Session Session=sessionFactory.openSession(); //我还尝试了:Session Session=sessionFactory.getCurrentSession(); 从上面的代码

它编译和部署,但当我打开一个页面时,而不是获取身份验证失败:密钥错误等。我获取身份验证失败:尝试sessionFactory时无法打开连接。openConnection() 当我 身份验证失败:没有绑定到线程的Hibernate会话,并且配置不允许在此创建非事务会话 在存储库中尝试Session Session=sessionFactory.getCurrentSession();时


我真的很想设法从我的数据库中获取这些数据。任何帮助都将不胜感激!非常感谢您的第一次尝试,默认spring context.xml的内容是什么?组件扫描是否包括您的包?我会认为
@RepositoryRestResource
声明on会使这个bean对您可用,但我以前没有使用过spring data REST,所以我不确定。

你好,Kevin,非常感谢!也感谢您在github上共享的非常有用的实现;)我的context.xml在我上面文章的“p.S”部分(在尝试2和尝试3之前..我很感激这篇文章可能包含太多的信息,但我希望尽可能详细)。为了让解决这个问题变得简单一点,您可以尝试创建自己的
UserSecurityRepository
接口实现。我想知道存储库接口是否会让这里的事情变得混乱,尽管我认为它应该可以工作。请查看
FakeUserSecurityRepositoryImpl
类以获取指导。只需插入一个JdbcTemplate并通过它进行实际查询即可。谢谢Kevin,但在attemp2和Attemp3中,我分别使用entitymanager和sessionfactory提供了自己的存储库
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]
<!--<sec:session-management session-fixation-protection="none"/>-->
@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;
    }