1. 概述

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

2. UserDetailsService

UserDetailsService 接口用于检索与用户相关的信息。它有一个名为 loadUserByUsername() 的方法,可以重写以自定义查找用户的过程。

DaoAuthenticationProvider 在身份验证过程中使用它来加载用户的详细信息。

3. 用户模型

为了存储用户,我们将创建一个名为 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. 获取用户

为了根据用户名获取用户,我们将使用 Spring Data 创建一个 DAO 类,扩展 JpaRepository 接口:

public interface UserRepository extends JpaRepository<User, Long> {

    User findByUsername(String username);
}

5. UserDetailsService

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

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

在这个方法中,我们使用 DAO 获取 User 对象,如果存在,我们将它包装到一个实现了 UserDetailsMyUserPrincipal 对象中,并返回:

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

让我们定义 MyUserPrincipal 类如下:

public class MyUserPrincipal implements UserDetails {
    private User user;

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

6. Spring 配置

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

6.1. 注解配置

为了启用我们的自定义 UserDetailsService,只需将其作为bean添加到我们的应用程序上下文中即可。

由于我们使用了 @Service 注解配置了类,应用在组件扫描期间会自动检测到它,并会将这个类转换为一个bean。所以在这里我们不需要做其他事情。

或者,我们可以:

  • 使用 AuthenticationManagerBuilder#userDetailsService 方法将它配置到 authenticationManager
  • 将其设置为自定义 authenticationProvider 的属性,然后使用 AuthenticationManagerBuilder#authenticationProvider 函数注入

6.2. XML配置

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

<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. 其他基于数据库的身份验证选项

AuthenticationManagerBuilder 提供了另一种方法来在我们的应用中配置基于JDBC的身份验证。

我们需要使用 AuthenticationManagerBuilder.jdbcAuthentication 配置一个 DataSource 实例。如果我们的数据库遵循 Spring Security的用户模式,那么默认配置将非常适合我们。

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

这种配置产生的 JdbcUserDetailsManager 实体也实现了 UserDetailsService

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

如果我们确实需要更高的灵活性,精确控制应用程序如何获取用户详细信息,那么我们将选择本教程中介绍的方法。

8. 总结

总之,本文展示了如何创建一个基于持久数据的Spring自定义 UserDetailsService

实现代码可以在 GitHub项目 中找到 - 这是一个基于Maven的项目,可以直接导入并运行,因为它是现成的。