Spring Security 已经废弃了 MessageDigestPasswordEncoder,推荐使用 BCryptPasswordEncoder
private static BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
@GetMapping("performance")public void performance() {StopWatch stopWatch = new StopWatch();String password = "Abcd1234";stopWatch.start("MD5");//MD5DigestUtils.md5Hex(password);stopWatch.stop();stopWatch.start("BCrypt(10)");//代价因子为10的BCryptString hash1 = BCrypt.gensalt(10);BCrypt.hashpw(password, hash1);System.out.println(hash1);stopWatch.stop();stopWatch.start("BCrypt(12)");//代价因子为12的BCryptString hash2 = BCrypt.gensalt(12);BCrypt.hashpw(password, hash2);System.out.println(hash2);stopWatch.stop();stopWatch.start("BCrypt(14)");//代价因子为14的BCryptString hash3 = BCrypt.gensalt(14);BCrypt.hashpw(password, hash3);System.out.println(hash3);stopWatch.stop();log.info("{}", stopWatch.prettyPrint());}
制作 8 位密码长度的 MD5 彩虹表需要 5 个月,那么对于 BCrypt 来说,可能就需要几十年,大部分黑客应该都没有这个耐心。
@GetMapping("better")public UserData better(@RequestParam(value = "name", defaultValue = "zhuye") String name, @RequestParam(value = "password", d efaultValue = "Abcd1234")String password) {UserData userData = new UserData();userData.setId(1L);userData.setId(1L);userData.setName(name);//保存哈希后的密码userData.setPassword(passwordEncoder.encode(password));userRepository.save(userData);//判断密码是否匹配log.info("match ? {}", passwordEncoder.matches(password, userData.getPassword()));return userData;}
我们的密码保存方式: "password": "$2a$10$wPWdQwfQO2lMxqSIb6iCROXv7lKnQq5XdMO96iCYCj7boK9pk6QPC" //格式为:$$$ 第一个$后的 2a 代表算法版本,第二个$后的 10 是代价因子(默认是 10,代表 2 的 10 次方次哈希),第三个$后的 22 个字符是盐,再后面是摘要。