SpringSecurity

SpringSecurity基础

Posted by lily on May 15, 2023

spring security

使用BCryptPasswordEncoder进行密码加密和校验的Spring Security实现

在Spring Security中,我们可以使用BCryptPasswordEncoder来对密码进行加密和校验。下面是相关步骤的总结:

BCryptPasswordEncoder作为密码加密器

将其注入到Spring容器中,可以在配置类中添加以下代码:

   @Configuration
   public class SecurityConfig extends WebSecurityConfigurerAdapter {
   
       @Bean
       public PasswordEncoder passwordEncoder() {
           return new BCryptPasswordEncoder();
       }
   
       // 其他配置...
   }

这样,BCryptPasswordEncoder就可以在应用程序中被使用了。

在用户认证服务中查询数据库并验证密码,实现UserDetailsService接口的loadUserByUsername方法:

   @Service
   public class UserDetailsServiceImpl implements UserDetailsService {
   
       @Autowired
       private UserRepository userRepository;
   
       @Autowired
       private PasswordEncoder passwordEncoder;
   
       @Override
       public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
           User user = userRepository.findByUsername(username);
           if (user == null) {
               throw new UsernameNotFoundException("User not found");
           }
   
           // 校验密码
           String rawPassword = user.getPassword(); // 从数据库中获取已加密的密码
           if (!passwordEncoder.matches(rawPassword, userEnteredPassword)) {
               throw new BadCredentialsException("Invalid password");
           }
   
           // 创建并返回用户详细信息
           // ...
       }
   }

关于BCrypt密码加密器的盐(salt)的概念。

BCrypt加密算法会自动生成一个随机的盐,并将盐与密码一起进行哈希处理,然后将哈希结果存储在数据库中。在密码校验时,盐会从存储的哈希结果中提取出来,并与用户输入的密码进行比较,以验证密码是否匹配。

Spring Security的BCryptPasswordEncodermatches方法中会自动提取并使用存储的哈希结果中的盐进行密码比较。下面是BCryptPasswordEncodermatches方法的简化版本的伪代码:

public boolean matches(CharSequence rawPassword, String encodedPassword) {
    // 从数据库中提取盐值
    String salt = encodedPassword.substring(0, 29);
    
    // 对用户输入的密码进行哈希处理
    String hashedPassword = hash(rawPassword, salt);
    
    // 比较哈希结果
    return hashedPassword.equals(encodedPassword);
}

在这个伪代码中,encodedPassword是存储在数据库中的加密密码,包含盐和哈希结果。rawPassword是用户输入的密码。matches方法首先从encodedPassword中提取前29个字符作为盐,然后使用盐对rawPassword进行哈希处理,生成一个哈希结果。最后,比较生成的哈希结果与encodedPassword中的哈希结果是否相等,以确定密码是否匹配。

由于matches方法会自动提取盐并进行比较,您无需手动存储和管理盐。整个过程由BCryptPasswordEncoder负责处理,确保密码的正确比较和校验。

loadUserByUsername方法中,我们首先通过用户名从数据库中查询用户信息。然后,使用BCryptPasswordEncodermatches方法将用户输入的密码与数据库中存储的加密密码进行比较。如果密码匹配,则认证成功;否则,抛出异常表示密码不正确。

需要注意的是,BCryptPasswordEncodermatches方法会自动从加密后的密码中提取盐值,并将其用于密码比较,无需手动解密。

通过以上配置和代码,Spring Security会自动处理密码的加密和校验逻辑,您只需要实现UserDetailsService接口中的loadUserByUsername方法,并返回正确的用户信息。

总结一下使用BCryptPasswordEncoder进行密码加密和校验的关键点:

  • 配置BCryptPasswordEncoder作为密码加密器,并注入到Spring容器中。
  • 在用户认证服务中查询数据库并验证密码时,通过BCryptPasswordEncodermatches方法进行密码校验,无需手动解密和提取盐值。

Filter的自定义注册和配置

filter基本用法

  1. doFilter方法中的 filterChain.doFilter(request, response);是将请求传递给下一个filter,如果没有下一个filter则传递给servlet。
  2. 每个filter执行完之后需要手动放行,因为默认是不放行的,因此若不在编码中显示放行之后的servlet或filter则不会被访问到。
  3. return语句,若在filter中使用return结束方法,则最后按责任链执行时该filter不会接着filterChain.doFilter(request, response);执行,但是后面的filter和servlet被执行。

security中的过滤器体系链

  1. Spring Security 的核心主要是一系列的过滤器链。这些过滤器本质上是一连串的Filter, 然后又以一个独立的Filter的形式插入到Filter Chain里,其名为FilterChainProxy。

  2. Spring Security 在 Servlet 的过滤链(filter chain)中注册了一个过滤器 FilterChainProxy,它会把请求代理到 Spring Security 自己维护的多个过滤链,每个过滤链会匹配一些 URL,如果匹配则执行对应的过滤器。过滤链是有顺序的,一个请求只会执行第一条匹配的过滤链。Spring Security 的配置本质上就是新增、删除、修改过滤器。

filter