java - 如何使用 Spring Security 以编程方式验证 `User` 并使用我的 `UserDetailsServie` 实现?

标签 java spring-security spring-data-jpa

我想将 spring security UserDetailsS​​ervice 与 spring data jpa CrudRepository 接口(interface)一起使用。 委托(delegate)人由实现 UserDetailsUser 实体表示:

@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 

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

<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>

它引用 UserDetailsS​​ervice 类型的 bean userDaoCrudRepository:

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;
}

现在我想在 jUnit 测试中以编程方式验证 User 对象。

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

然后我尝试使用 UserDao 而不是 UserDetailsManager 但我的 UserDao 没有验证 User,但是仅从数据库加载它。在这种情况下,不需要 spring-security.xml

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

编辑

当我尝试使用 @Qualifier Autowiring 我的 UserDao 并在没有它的情况下使用 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

最佳答案

您可以使用 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 的异常,您可以指定您想要哪一个。例如,如果您想要一个名为 userDao 的 UserDetailsS​​ervice bean,您可以使用:

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

...

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

关于java - 如何使用 Spring Security 以编程方式验证 `User` 并使用我的 `UserDetailsServie` 实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29512391/

相关文章:

java - 什么是java :comp/env?

java - 绑定(bind)jar :test-jar to package phase

java - 没有本地数据库的 TDD?

javascript - 如何在 AngularJS 中捕获/处理后端异常

java - 检索 Spring Security 的身份验证,即使在具有过滤器 ="none"的公共(public)页面上

java - JPA : entity object is not appeared in the H2 console

java - 回滚不起作用

java - 基于 Spring Security token 的身份验证

Spring 数据预测

java - 如何在没有数据冗余的情况下与JPA实体建立递归关系?