DaoAuthenticationProvider和UserDetailsService

DaoAuthenticationProvider 是 Spring Security 中最常用的认证提供器之一,专门用于处理基于数据库或其他持久化存储的用户认证。它结合了 UserDetailsServicePasswordEncoder,通过从数据库中加载用户的详细信息来进行身份认证。

核心功能

  • 用户认证:通过 UserDetailsService 加载用户信息。
  • 密码验证:通过 PasswordEncoder 对比用户输入的密码和存储的加密密码。
  • 用户锁定/禁用:可以处理用户的账户是否锁定、禁用或过期等状态。
  • 权限管理:通过 UserDetails 提供用户的权限信息,供后续授权决策使用。

关键组成部分

  1. UserDetailsService:负责从存储中加载用户信息,它的 loadUserByUsername 方法用于查找用户并返回一个 UserDetails 对象(包含用户名、密码、权限等信息)。

  2. PasswordEncoder:用于加密和验证用户密码。DaoAuthenticationProvider 通过 PasswordEncoder 来确保用户输入的密码与存储的加密密码一致,常用的加密器有 BCryptPasswordEncoder

  3. UserDetails:封装用户的详细信息,如用户名、密码和权限等。DaoAuthenticationProvider 会根据 UserDetails 验证密码,并检查用户是否锁定、禁用或账户是否过期。

认证流程

  1. 用户提交用户名和密码进行登录。
  2. DaoAuthenticationProvider 调用 UserDetailsService,根据用户名加载用户信息。
  3. 加载后的用户信息(UserDetails)包含存储在数据库中的加密密码。
  4. 使用 PasswordEncoder 对用户提交的密码进行加密,并与存储的加密密码进行比较。
  5. 如果密码匹配且用户未被锁定或禁用,认证成功,返回一个 AuthenticatedAuthentication 对象。
  6. 如果密码不匹配或用户被锁定/禁用,认证失败。

自定义 UserDetailsService
UserDetailsService 的核心作用是加载用户的信息,通常你需要自定义这个接口来从数据库中加载用户。

import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 从数据库或其他存储中加载用户信息
        // 假设从数据库加载用户,使用 username 查询
        User user = userRepository.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("User not found");
        }

        // 将 User 转换为 Spring Security 的 UserDetails 对象
        return new org.springframework.security.core.userdetails.User(
            user.getUsername(),
            user.getPassword(),
            user.getAuthorities()  // 用户的角色和权限
        );
    }
}

在上面的例子中,CustomUserDetailsService 实现了 UserDetailsService 接口的 loadUserByUsername 方法,用于根据用户名从存储中查找用户信息,并返回一个 UserDetails 对象,Spring Security 会使用这个对象来验证用户身份。

DaoAuthenticationProvider 的常见配置

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final CustomUserDetailsService userDetailsService;

    public SecurityConfig(CustomUserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 配置 DaoAuthenticationProvider 使用自定义的 UserDetailsService
        auth.authenticationProvider(daoAuthenticationProvider());
    }

    @Bean
    public DaoAuthenticationProvider daoAuthenticationProvider() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(userDetailsService);  // 设置 UserDetailsService
        provider.setPasswordEncoder(passwordEncoder());      // 设置 PasswordEncoder
        return provider;
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();  // 使用 BCrypt 作为密码加密器
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .antMatchers("/login").permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .loginPage("/login")
            .permitAll()
            .and()
            .logout()
            .permitAll();
    }
}

重要方法

  • setUserDetailsService(UserDetailsService userDetailsService):指定用于加载用户的 UserDetailsService 实现。

  • setPasswordEncoder(PasswordEncoder passwordEncoder):设置密码加密器,验证用户输入的密码时会使用该加密器进行匹配。

  • authenticate(Authentication authentication):进行认证的核心方法,使用 UserDetailsService 加载用户信息,比较密码并返回认证结果。

认证逻辑分析

  1. authenticate 方法

    • DaoAuthenticationProvider 接收到用户提交的 Authentication 对象(包含用户名和密码)。
    • 调用 UserDetailsServiceloadUserByUsername 方法,查找用户信息。
    • 从用户信息中获取加密后的密码,并使用 PasswordEncoder 验证用户提交的明文密码。
    • 如果密码匹配,则认证成功;否则,抛出认证失败异常。
  2. 用户状态检查

    • 检查用户的账户是否过期、是否被锁定或禁用。如果存在问题,认证也会失败。

总结

  • DaoAuthenticationProvider 是 Spring Security 中用于处理基于用户名和密码的认证的核心类,主要通过 UserDetailsServicePasswordEncoder 实现用户信息加载和密码验证。
  • 它广泛用于数据库、LDAP、内存等多种存储方式的认证场景,可以结合各种 UserDetailsServicePasswordEncoder 实现灵活的认证流程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值