SpringSecurity04

密码加密

基础密码加密

  1. SpringSecurity提供的加密接口
    public interface PasswordEncoder {
    
        //加密
        String encode(CharSequence rawPassword);
    
        //校验, 检查一个明文密码是否和一个密文密码一致
        boolean matches(CharSequence rawPassword, String encodedPassword);
    }
  2. 创建PasswordEncoder实现类
    @Component
    public class MyPasswordEncoder implements PasswordEncoder {
    
        @Override
        public String encode(CharSequence rawPassword) {
    
            return privateEncode(rawPassword);
        }
    
        @Override
        public boolean matches(CharSequence rawPassword, String encodedPassword) {
    
            // 1.对明文密码加密
            String encodedFormPassword = privateEncode(rawPassword);
    
            // 比较
            return Objects.equals(encodedPassword, encodedFormPassword);
    
        }
    
        private String privateEncode(CharSequence rawPassword) {
            try {
                // 1.创建MessageDigest对象
                String algorithm = "MD5";
                MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
    
                // 2.获取rawPassword的字节数组
                byte[] input = ((String) rawPassword).getBytes();
    
                // 3.加密
                byte[] output = messageDigest.digest(input);
    
                // 4.转换为16进制数对应的字符
                String encoded = new BigInteger(1, output).toString(16);
    
                return encoded;
    
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
    
            return null;
        }
    }
  3. 在SpringSecurity的配置类中装配
        @Autowired
        private MyPasswordEncoder myPasswordEncoder;
    
        @Override
        protected void configure(AuthenticationManagerBuilder builder) throws Exception {
    
            builder.
                userDetailsService(userDetailsService).passwordEncoder(myPasswordEncoder);
    
        }
  4. 潜在的风险
    1. 固定的明文对应固定的密文, 虽然不能从密文通过算法破解反推回明文,  但可以借助彩虹表"碰撞"出来.
    2. 为解决该问题, 我们可以采用带盐值的加密.

带盐值的加密

  1. 概念
    1. 借用生活中烹饪时加食盐的不同, 菜的味道不同. 在加密时每次使用随机生成的盐值, 让加密结果不固定.
    2. SpringSecurity中使用BCryptPasswordEncoder类完成带盐值的加密.
  2. BCryptPasswordEncoder
    1. 加密(encode)
      • 使用(SHA-256+随机盐+密钥)把用户输入的密码进行hash处理,得到密码的hash值, 然后将其存入数据库中.
  3. 测试
    public class SecurityTest {
    
        public static void main(String[] args) {
    
            // 1.创建BCryptPasswordEncoder对象
            BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    
            // 2.准备明文字符串
            String rawPassword = "123123";
    
            // 3.加密
            String encode = passwordEncoder.encode(rawPassword);
            System.out.println(encode);
            // $2a$10$L5ENCHehwTCFlTIjvn5sfel6YOG/TWK.SVH/NbTvqI15MaFSQV6D.
            // $2a$10$J04bVP3gxJghPSrH/t5PJuKw.7KYJvOydQOfI6HTndE/gefetr.SC
            // $2a$10$QT94LTwIqBw8F3ITsQtxuuiFsOKgBfcdR858xGzYfkh6dGs5FIiCS
    
        }
    }
    
    class EncodeTest {
        
        public static void main(String[] args) {
            
            //1.准备明文字符串
            String rawPassword = "123123";
            
            //2.准备密文字符串
            String encodedPassword = "$2a$10$QT94LTwIqBw8F3ITsQtxuuiFsOKgBfcdR858xGzYfkh6dGs5FIiCS";
            
            //3.创建BCryptPasswordEncoder对象
            BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
            
            //4.比较
            boolean result = passwordEncoder.matches(rawPassword, encodedPassword);
            System.out.println(result);
        }
    }
  4. 使用
    1. 创建BCryptPasswordEncoder对象, 传给passwordEncoder()方法
          //每次调用该方法时会检查IOC容器中是否有了对应的bean, 如果有, 就不会真正执行该函数了, 因为bean默认是单例的.
          //@Scope(value="") - 使用该注解控制是否单例
          @Bean
          public BCryptPasswordEncoder getBCryptPasswordEncoder() {
      
              return new BCryptPasswordEncoder();
          }
      
          @Override
          protected void configure(AuthenticationManagerBuilder builder) throws Exception {
      
              builder
                  .userDetailsService(userDetailsService).passwordEncoder(getBCryptPasswordEncoder());
              ;
          }
原文地址:https://www.cnblogs.com/binwenhome/p/12743403.html