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

最后修改: 2016年 10月 19日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

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

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

2. UserDetailsService

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.

UserDetailsService接口用于检索用户相关数据。它有一个名为loadUserByUsername()的方法,可以被重写以定制寻找用户的过程。

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

它被DaoAuthenticationProvider使用,以在认证期间加载关于用户的详细信息。

3. The User Model

3.用户模式

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

为了存储用户,我们将创建一个User实体,它被映射到一个数据库表,具有以下属性。

@Entity
public class User {

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

4.检索一个用户

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

5.UserDetailsService

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

为了提供我们自己的用户服务,我们将需要实现UserDetailsService接口。

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

我们将创建一个名为MyUserDetailsService的类,重写接口的loadUserByUsername()方法。

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:

在这个方法中,我们使用DAO检索User对象,如果它存在,就把它包装成MyUserPrincipal对象,实现UserDetails,并返回它。

@Service
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;

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

6.Spring配置

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

我们将演示两种类型的Spring配置。为了使用我们自定义的UserDetailsService实现,XML和基于注解的配置是必要的。

6.1. Annotation Configuration

6.1.注释配置

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

我们需要做的就是启用我们的自定义UserDetailsService,将其作为一个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

6.2.XML配置

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:

另一方面,对于XML配置,我们需要定义一个类型为MyUserDetailsService的bean,并将其注入Spring的authentication-providerbean。

<bean id="myUserDetailsService" 
  class="org.baeldung.security.MyUserDetailsService"/>

<security:authentication-manager>
    <security:authentication-provider 
      user-service-ref="myUserDetailsService" >
        <security:password-encoder ref="passwordEncoder">
        </security:password-encoder>
    </security:authentication-provider>
</security:authentication-manager>
    
<bean id="passwordEncoder" 
  class="org.springframework.security
  .crypto.bcrypt.BCryptPasswordEncoder">
    <constructor-arg value="11"/>
</bean>

7. Other Database-backed Authentication Options

7.其他以数据库为基础的认证选项

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

AuthenticationManagerBuilder提供了另一种方法来配置我们应用程序中基于JDBC的认证。

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.

我们必须用一个DataSource实例来配置AuthenticationManagerBuilder.jdbcAuthentication。如果我们的数据库遵循Spring用户模式,那么默认配置将很适合我们。

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

我们在上一篇文章中已经看到了使用这种方法的基本配置。

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

由该配置产生的JdbcUserDetailsManager实体实现了UserDetailsServicetoo。

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

8.结论

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

总而言之,在这篇文章中,我们展示了如何创建一个基于Spring的UserDetailsService,并以持久性数据为支撑。

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的项目,所以应该很容易导入并按原样运行。