如何使用spring security以编程方式验证`User`并使用我的`UserDetailsS​​ervie`实现?

时间:2015-04-08 10:39:35

标签: java spring-security spring-data-jpa

我想将spring security UserDetailsService与spring data jpa CrudRepository接口一起使用。 Principal由实现User的{​​{1}}实体代表:

UserDetails

我有spring-security.xml配置文件:

@Entity
public class User implements UserDetails {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String username;
    private String password;

    //other methods of UserDetails 

它指的是类型<beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd"> <authentication-manager> <!-- refers to spring data repository bean org.baeldung.SpringDataAuditDemo.dao.repos.UserDao --> <authentication-provider user-service-ref="userDao" /> </authentication-manager> </beans:beans> userDao的bean UserDetailsService

CrudRepository

现在我想在jUnit测试中以编程方式验证public interface UserDao extends CrudRepository<User, Long>, UserDetailsService { // @Override @Query(value = "select u from User u where u.username=:username") public UserDetails loadUserByUsername(@Param("username") String username) throws UsernameNotFoundException; } 对象。

我希望在验证User时运行UserDao.loadUserByUsername方法。 为此我想使用User,但它实现了org.springframework.security.provisioning.UserDetailsManager接口以及我的UserDetailsService。因此我得到两个相同类型的bean存在异常!!!

然后我尝试使用UserDao而不是UserDao,但我的UserDetailsManager不对UserDao进行身份验证,而只是从db加载它。在这种情况下,不需要User

如何使用spring security default spring-security.xml以编程方式验证User并使用我的DaoAuthenticationProvider实现?

修改

当我尝试使用UserDetailsServie UserDao@Qualifier无法使用UserDetailsManager时,我遇到了这个例外:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.security.provisioning.UserDetailsManager] 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.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1118)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:967)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:862)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:494)
... 28 more

1 个答案:

答案 0 :(得分:1)

您可以使用AuthenticationManager以编程方式对自定义UserDetailsS​​ervice进行身份验证。例如,以下内容适用于JUnit测试:

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class SecurityConfigTests {

    @Autowired
    private AuthenticationManager manager;

    @Before
    public void setup() {
        SecurityContext context = SecurityContextHolder.createEmptyContext();
        Authentication user = manager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
        context.setAuthentication(user);

        SecurityContextHolder.setContext(context);
    }
    ...
}

如果您有多个相同类型的bean,则可以使用Qualifier注释。这意味着如果您遇到存在两个相同类型的bean的异常,则可以指定所需的bean。例如,如果您想要一个名为userDao的UserDetailsS​​ervice bean,则可以使用:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

...

@Qualifier("userDao")
@Autowired
UserDetailsService userDao;