Spring Security: Authentication with a Database-backed UserDetailsService – Spring的安全 用数据库支持的UserDetailsService进行认证

最后修改: 2016年 10月 19日


1. Overview


In this article, we will show how to create a custom database-backed UserDetailsService for authentication with Spring Security.

在这篇文章中,我们将展示如何创建一个自定义数据库支持的UserDetailsService,用于Spring Security的认证。

2. UserDetailsService


The UserDetailsService interface is used to retrieve user-related data. It has one method named loadUserByUsername() which can be overridden to customize the process of finding the user.


It is used by the DaoAuthenticationProvider to load details about the user during authentication.


3. The User Model


For storing users, we will create a User entity that is mapped to a database table, with the following attributes:


public class User {

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

    @Column(nullable = false, unique = true)
    private String username;

    private String password;

    // standard getters and setters

4. Retrieving a User


For the purpose of retrieving a user associated with a username, we will create a DAO class using Spring Data by extending the JpaRepository interface:

为了检索与用户名相关的用户,我们将通过扩展JpaRepository接口,使用Spring Data创建一个DAO类。

public interface UserRepository extends JpaRepository<User, Long> {

    User findByUsername(String username);

5. The UserDetailsService


In order to provide our own user service, we will need to implement the UserDetailsService interface.


We’ll create a class called MyUserDetailsService that overrides the method loadUserByUsername() of the interface.


In this method, we retrieve the User object using the DAO, and if it exists, wrap it into a MyUserPrincipal object, which implements UserDetails, and returns it:


public class MyUserDetailsService implements UserDetailsService {

    private UserRepository userRepository;

    public UserDetails loadUserByUsername(String username) {
        User user = userRepository.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException(username);
        return new MyUserPrincipal(user);

Let’s define the MyUserPrincipal class as follows:

让我们定义 MyUserPrincipal类,如下所示。

public class MyUserPrincipal implements UserDetails {
    private User user;

    public MyUserPrincipal(User user) {
        this.user = user;

6. Spring Configuration


We will demonstrate both types of Spring configurations: XML and annotation-based, which are necessary in order to use our custom UserDetailsService implementation.


6.1. Annotation Configuration


All we need to do to enable our custom UserDetailsService is add it to our application context as a bean.


Since we configured our class with the @Service annotation, the application will automatically detect it during component-scan, and it will create a bean out of this class. Therefore, there isn’t anything else we need to do here.

由于我们用@Service 注解配置了我们的类,应用程序将在组件扫描过程中自动检测到它,并且它将从这个类中创建一个bean。因此,我们在这里不需要做任何其他事情。

Alternatively, we can:


  • configure it in the authenticationManager using the AuthenticationManagerBuilder#userDetailsService method
  • set it as a property in a custom authenticationProvider bean, and then inject that using the AuthenticationManagerBuilder# authenticationProvider function

6.2. XML Configuration


On the other hand, for the XML configuration we need to define a bean with type MyUserDetailsService, and inject it into Spring’s authentication-provider bean:


<bean id="myUserDetailsService" 

      user-service-ref="myUserDetailsService" >
        <security:password-encoder ref="passwordEncoder">
<bean id="passwordEncoder" 
    <constructor-arg value="11"/>

7. Other Database-backed Authentication Options


The AuthenticationManagerBuilder offers one other method to configure JDBC-based authentication in our application.


We’ll have to configure the AuthenticationManagerBuilder.jdbcAuthentication with a DataSource instance. If our database follows the Spring User Schema, then the default configurations will suit us well.


We have seen a basic configuration using this approach in a previous post.


The JdbcUserDetailsManager entity resulting from this configuration implements the UserDetailsService too.


As a result, we can conclude that this configuration is easier to implement, especially if we’re using Spring Boot that automatically configures the DataSource for us.

因此,我们可以得出结论,这种配置更容易实现,特别是如果我们使用的是Spring Boot,它可以自动为我们配置DataSource

If we need, anyway, a higher level of flexibility, customizing exactly how the application will fetch the user details, then we’ll opt for the approach we followed in this tutorial.


8. Conclusion


To sum up, in this article we’ve shown how to create a custom Spring-based UserDetailsService backed by persistent data.


The implementation can be found in the GitHub project – this is a Maven based project, so it should be easy to import and run as it is.

该实现可以在GitHub项目中找到 – 这是一个基于Maven的项目,所以应该很容易导入并按原样运行。