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