【SpringBoot】MD5加盐算法的详解

打印 上一主题 下一主题

主题 963|帖子 963|积分 2889

目录
一、什么是加盐算法
二、如何实现加盐算法
2.1 加盐算法代码实现
2.2 注册页面中进行密码加盐
2.3 登录页面进行加盐的解密
2.4 注册和登录

一、什么是加盐算法

加盐算法是一种用于增强密码安全性的技能。这种技能通过在密码存储过程中添加一个随机天生的盐值(salt),来增长密码被破解的难度。举个例子:
在一样平常生活中,做菜是生活中的基本操作。炒青菜餐桌中必备的一道菜,不同的人炒青菜放盐的程度是不同的,换句话来说不同的人炒同一种菜放盐的多与少是一种随机的操作。因此,在注册账号时,不同用户在注册时难免会利用雷同的密码。加盐算法会根据不同的用户天生一串随机的字符串与用户所输入的密码进行联合天生一个最终的结果值,而这个最终值得到的就是加密后的密码。
具体来说,加盐加密的过程如下:
   

  • 天生盐值:后端在存储一个密码时,首先会随机天生一个盐值。这个盐值是一个随机字符串,用于增长密码的复杂性。
  • 联合盐值和密码:将天生的盐值和用户输入的密码进行有规则的联合,通常是将盐值附加在密码的前面或背面,或者通过其他方式进行组合。
  • 加密处理:将联合后的数据利用加密算法进行加密。常见的加密算法包括MD5、SHA-256等。在Spring Security中,还可以利用更强大的加密方式,如BCrypt。本期讲解利用MD5。
  • 存储加密后的数据和盐值:将加密后的数据和盐值按照肯定规则组合起来,并存储在数据库中。通常,盐值会被保存在与加密密码雷同的记录中,以便在验证用户密码时利用。
  
二、如何实现加盐算法

2.1 加盐算法代码实现

首先,我们要了解到:
天生一个随机盐值可利用 UUID UUID 是一个128比特的数值,通常由 32 个 16 进制数字组成,并以连字号分为五段,例如:550e8400-e29b-41d4-a716-446655440000,因此可利用 replace 方法去除 -
天生一个 MD5 散列值,可利用 DigestUtils类 中的 .md5DigestAsHex 方法将天生的随机盐值 salt password 联合,并通过 .getBytes 将联合后的字符串转换成一个字节数组即 .getBytes(StandardCharsets.UTF_8)
此外需要留意的是:
   

  • MD5(Message-Digest Algorithm 5)是一种广泛利用的散列函数,可以产生一个128位(16字节)的散列值,通常表示为32位的十六进制数。
  • md5DigestAsHex 是 DigestUtils 类中的一个静态方法。这个方法接受一个字节数组作为输入,盘算其MD5散列值,并将结果转换为十六进制字符串。
  • StandardCharsets.UTF_8 是一个表示UTF-8字符集的常量,它指定了字符串到字节数组的编码方式。
  代码实现:
  1. /**
  2. * 加密工具类
  3. */
  4. public class PasswordUtils {
  5.     public static String encrypt(String password){
  6.         // 1.盐值
  7.         String salt = UUID.randomUUID().toString().replace("-","");
  8.         // 2.将盐值+密码进行 md5 得到最终密码
  9.         String finalPassword = DigestUtils.md5DigestAsHex((salt+password).getBytes(StandardCharsets.UTF_8));
  10.         // 3.将盐值和最终密码返回
  11.         return salt+"$"+finalPassword;
  12.     }
  13.     /**
  14.      * 加盐验证
  15.      * @param password 待验证的密码
  16.      * @param dbPassword 数据库中的密码:盐值$最终密码
  17.      * @return
  18.      */
  19.     public static boolean decrypt(String password,String dbPassword) {
  20.         if(!StringUtils.hasLength(password) || !StringUtils.hasLength(dbPassword)
  21.         || dbPassword.length() != 65) {
  22.             return false;
  23.         }
  24.         // 1.得到盐值
  25.         String[] dbPasswordArray = dbPassword.split("\\$") ;
  26.         if (dbPasswordArray.length != 2) {
  27.             return false;
  28.         }
  29.         //盐值
  30.         String salt = dbPasswordArray[0];
  31.         //最终正确密码
  32.         String dbFinalPassword = dbPasswordArray[1];
  33.         // 2.加密待验证的密码
  34.         String finalPassword = DigestUtils.md5DigestAsHex((salt+password).getBytes(StandardCharsets.UTF_8));
  35.         // 3.对比
  36.         if (finalPassword.equals(dbFinalPassword)) {
  37.             return true;
  38.         }
  39.         return false;
  40.     }
  41.     public static void main(String[] args) {
  42.         // 得到盐值和最终密码一共65位
  43.         System.out.println(encrypt("111"));
  44.     }
  45. }
复制代码
在该类中天生一个 main 方法,测试最后天生的字符串符不符合预期,输出结果:

将上述的字符串,定义为一个字符串,验证是否加密成功。 
  1.     public static void main(String[] args) {
  2. /*        // 得到盐值和最终密码一共65位
  3.         System.out.println(encrypt("111"));*/
  4.         String dbPassword = "0f0d62e88c6c41dc83163e2813147111$b7321a14e1e5f3360a0d0d59e2b3cd6e";
  5.         System.out.println("当密码为123时:"+decrypt("123",dbPassword));
  6.         System.out.println("当密码为111时:"+decrypt("111",dbPassword));
  7.     }
复制代码
 


2.2 注册页面中进行密码加盐

  1.     /**
  2.      * 注册
  3.      * @param userinfo
  4.      * @return
  5.      */
  6.     @RequestMapping("/reg")
  7.     public ResultAjax reg(Userinfo userinfo) {
  8.        // 1.校验参数
  9.         if (userinfo == null || !StringUtils.hasLength(userinfo.getUsername()) ||
  10.         !StringUtils.hasLength(userinfo.getPassword())) {
  11.             return ResultAjax.fail(-1,"异常");
  12.         }
  13.         // 实现密码加盐
  14.         userinfo.setPassword(PasswordUtils.encrypt(userinfo.getPassword()));
  15.         // 2.请求接口 service 进行添加接口
  16.         int ret = userService.reg(userinfo);
  17.         // 3.将结果返回给前端
  18.         return ResultAjax.success(ret);
  19.     }
复制代码
2.3 登录页面进行加盐的解密

  1. /**
  2.      * 登录
  3.      * @param userinfoVO
  4.      * @return
  5.      */
  6.     @RequestMapping("/login")
  7.     public ResultAjax login(UserinfoVO userinfoVO, HttpServletRequest request) {
  8.         // 1.参数校验
  9.         if (userinfoVO == null || !StringUtils.hasLength(userinfoVO.getUsername())
  10.                 || !StringUtils.hasLength(userinfoVO.getPassword())) {
  11.             // 非法登录
  12.             return ResultAjax.fail(-1,"非法登录!");
  13.         }
  14.         // 2.根据用户名查询对象,判断用户名是否错误
  15.         Userinfo userinfo = userService.getUserByName(userinfoVO.getUsername());
  16.         if (userinfo == null && userinfo.getId() == 0) {
  17.             return ResultAjax.fail(-2,"账号或密码错误!");
  18.         }
  19.         // 3.使用对象中的密码和输入的密码进行对比,判断密码是否错误
  20.         // 加盐解密
  21.         if (!PasswordUtils.decrypt(userinfoVO.getPassword(),userinfo.getPassword())) {
  22.             return ResultAjax.fail(-2,"账号或密码错误!");
  23.         }
  24.         // 4.成功后将对象存储到 session 中
  25.         HttpSession session = request.getSession();
  26.         session.setAttribute(ApplicationVariable.SESSION_USERINFO_KEY,userinfo);
  27.         // 5.结果返回给用户
  28.         return ResultAjax.success(1);
  29.     }
复制代码
 此时查询数据库中,只有一条数据,下面再注册一个用户,观察是否天生密码。


2.4 注册和登录

注册页面
 输入用户名 lisi 和密码 123 后,提示注册成功。

在数据中查询对应的数据,验证密码 123 被加秘为一大串字符串。

再来到登录页面,输入用户名 lisi 和密码 123,提示登岸成功。 

跳转到个人页面。

注册页面和登录页面的讲解和源码在前两篇博客中已有详细的讲解,感爱好可以去看看。

本篇博客到这里就结束了,感谢各位的观看。 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

兜兜零元

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表