SpringBoot實現(xiàn)MD5加鹽算法的示例代碼
一、什么是加鹽算法
加鹽算法是一種用于增強密碼安全性的技術(shù)。這種技術(shù)通過在密碼存儲過程中添加一個隨機生成的鹽值(salt),來增加密碼被破解的難度。舉個例子:
在日常生活中,做菜是生活中的基本操作。炒青菜餐桌中必備的一道菜,不同的人炒青菜放鹽的程度是不同的,換句話來說不同的人炒同一種菜放鹽的多與少是一種隨機的操作。因此,在注冊賬號時,不同用戶在注冊時難免會使用相同的密碼。加鹽算法會根據(jù)不同的用戶生成一串隨機的字符串與用戶所輸入的密碼進行結(jié)合生成一個最終的結(jié)果值,而這個最終值得到的就是加密后的密碼。
具體來說,加鹽加密的過程如下:
生成鹽值:后端在存儲一個密碼時,首先會隨機生成一個鹽值。這個鹽值是一個隨機字符串,用于增加密碼的復(fù)雜性。
結(jié)合鹽值和密碼:將生成的鹽值和用戶輸入的密碼進行有規(guī)則的結(jié)合,通常是將鹽值附加在密碼的前面或后面,或者通過其他方式進行組合。
加密處理:將結(jié)合后的數(shù)據(jù)使用加密算法進行加密。常見的加密算法包括MD5、SHA-256等。在Spring Security中,還可以使用更強大的加密方式,如BCrypt。本期講解使用MD5。
存儲加密后的數(shù)據(jù)和鹽值:將加密后的數(shù)據(jù)和鹽值按照一定規(guī)則組合起來,并存儲在數(shù)據(jù)庫中。通常,鹽值會被保存在與加密密碼相同的記錄中,以便在驗證用戶密碼時使用。
二、如何實現(xiàn)加鹽算法
2.1 加鹽算法代碼實現(xiàn)
首先,我們要了解到:
生成一個隨機鹽值可使用 UUID ,UUID 是一個128比特的數(shù)值,通常由 32 個 16 進制數(shù)字組成,并以連字號分為五段,例如:550e8400-e29b-41d4-a716-446655440000,因此可使用 replace 方法去除 - 。
生成一個 MD5 散列值,可使用 DigestUtils類 中的 .md5DigestAsHex 方法將生成的隨機鹽值 salt 和 password 結(jié)合,并通過 .getBytes 將結(jié)合后的字符串轉(zhuǎn)換成一個字節(jié)數(shù)組即 .getBytes(StandardCharsets.UTF_8) 。
此外需要注意的是:
- MD5(Message-Digest Algorithm 5)是一種廣泛使用的散列函數(shù),可以產(chǎn)生一個128位(16字節(jié))的散列值,通常表示為32位的十六進制數(shù)。
- md5DigestAsHex 是 DigestUtils 類中的一個靜態(tài)方法。這個方法接受一個字節(jié)數(shù)組作為輸入,計算其MD5散列值,并將結(jié)果轉(zhuǎn)換為十六進制字符串。
- StandardCharsets.UTF_8 是一個表示UTF-8字符集的常量,它指定了字符串到字節(jié)數(shù)組的編碼方式。
代碼實現(xiàn):
/** * 加密工具類 */ public class PasswordUtils { public static String encrypt(String password){ // 1.鹽值 String salt = UUID.randomUUID().toString().replace("-",""); // 2.將鹽值+密碼進行 md5 得到最終密碼 String finalPassword = DigestUtils.md5DigestAsHex((salt+password).getBytes(StandardCharsets.UTF_8)); // 3.將鹽值和最終密碼返回 return salt+"$"+finalPassword; } /** * 加鹽驗證 * @param password 待驗證的密碼 * @param dbPassword 數(shù)據(jù)庫中的密碼:鹽值$最終密碼 * @return */ public static boolean decrypt(String password,String dbPassword) { if(!StringUtils.hasLength(password) || !StringUtils.hasLength(dbPassword) || dbPassword.length() != 65) { return false; } // 1.得到鹽值 String[] dbPasswordArray = dbPassword.split("\\$") ; if (dbPasswordArray.length != 2) { return false; } //鹽值 String salt = dbPasswordArray[0]; //最終正確密碼 String dbFinalPassword = dbPasswordArray[1]; // 2.加密待驗證的密碼 String finalPassword = DigestUtils.md5DigestAsHex((salt+password).getBytes(StandardCharsets.UTF_8)); // 3.對比 if (finalPassword.equals(dbFinalPassword)) { return true; } return false; } public static void main(String[] args) { // 得到鹽值和最終密碼一共65位 System.out.println(encrypt("111")); } }
在該類中生成一個 main 方法,測試最后生成的字符串符不符合預(yù)期,輸出結(jié)果:
將上述的字符串,定義為一個字符串,驗證是否加密成功。
public static void main(String[] args) { /* // 得到鹽值和最終密碼一共65位 System.out.println(encrypt("111"));*/ String dbPassword = "0f0d62e88c6c41dc83163e2813147111$b7321a14e1e5f3360a0d0d59e2b3cd6e"; System.out.println("當(dāng)密碼為123時:"+decrypt("123",dbPassword)); System.out.println("當(dāng)密碼為111時:"+decrypt("111",dbPassword)); }
2.2 注冊頁面中進行密碼加鹽
/** * 注冊 * @param userinfo * @return */ @RequestMapping("/reg") public ResultAjax reg(Userinfo userinfo) { // 1.校驗參數(shù) if (userinfo == null || !StringUtils.hasLength(userinfo.getUsername()) || !StringUtils.hasLength(userinfo.getPassword())) { return ResultAjax.fail(-1,"異常"); } // 實現(xiàn)密碼加鹽 userinfo.setPassword(PasswordUtils.encrypt(userinfo.getPassword())); // 2.請求接口 service 進行添加接口 int ret = userService.reg(userinfo); // 3.將結(jié)果返回給前端 return ResultAjax.success(ret); }
2.3 登錄頁面進行加鹽的解密
/** * 登錄 * @param userinfoVO * @return */ @RequestMapping("/login") public ResultAjax login(UserinfoVO userinfoVO, HttpServletRequest request) { // 1.參數(shù)校驗 if (userinfoVO == null || !StringUtils.hasLength(userinfoVO.getUsername()) || !StringUtils.hasLength(userinfoVO.getPassword())) { // 非法登錄 return ResultAjax.fail(-1,"非法登錄!"); } // 2.根據(jù)用戶名查詢對象,判斷用戶名是否錯誤 Userinfo userinfo = userService.getUserByName(userinfoVO.getUsername()); if (userinfo == null && userinfo.getId() == 0) { return ResultAjax.fail(-2,"賬號或密碼錯誤!"); } // 3.使用對象中的密碼和輸入的密碼進行對比,判斷密碼是否錯誤 // 加鹽解密 if (!PasswordUtils.decrypt(userinfoVO.getPassword(),userinfo.getPassword())) { return ResultAjax.fail(-2,"賬號或密碼錯誤!"); } // 4.成功后將對象存儲到 session 中 HttpSession session = request.getSession(); session.setAttribute(ApplicationVariable.SESSION_USERINFO_KEY,userinfo); // 5.結(jié)果返回給用戶 return ResultAjax.success(1); }
此時查詢數(shù)據(jù)庫中,只有一條數(shù)據(jù),下面再注冊一個用戶,觀察是否生成密碼。
2.4 注冊和登錄
注冊頁面
輸入用戶名 lisi 和密碼 123 后,提示注冊成功。
在數(shù)據(jù)中查詢對應(yīng)的數(shù)據(jù),驗證密碼 123 被加秘為一大串字符串。
再來到登錄頁面,輸入用戶名 lisi 和密碼 123,提示登陸成功。
跳轉(zhuǎn)到個人頁面。
注冊頁面和登錄頁面的講解和源碼在前兩篇博客中已有詳細的講解,感興趣可以去看看。
到此這篇關(guān)于SpringBoot實現(xiàn)MD5加鹽算法的示例代碼的文章就介紹到這了,更多相關(guān)SpringBoot MD5加鹽算法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot的實體類字段校驗的分組校驗具體實現(xiàn)步驟
分組校驗允許在不同場景下對同一實體類應(yīng)用不同的校驗規(guī)則,通過定義分組接口、在實體類和Controller中指定分組,以及全局異常處理,可以靈活控制校驗規(guī)則,本文介紹springboot的實體類字段校驗的分組校驗,感興趣的朋友一起看看吧2025-03-03rabbitmq basicReject/basicNack/basicRecover的區(qū)別及說明
這篇文章主要介紹了rabbitmq basicReject/basicNack/basicRecover的區(qū)別及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01Mybatis中SqlSession下的四大對象之執(zhí)行器(executor)
mybatis中sqlsession下的四大對象是指:executor, statementHandler,parameterHandler,resultHandler對象。這篇文章主要介紹了Mybatis中SqlSession下的四大對象之執(zhí)行器(executor),需要的朋友可以參考下2019-04-04