1、概念
(1)基本概念
對原有的內容進行編碼得到不同於原始內容但是能夠表示原有內容的數據。
在數據存儲密碼的時候如果不進行加密直接存儲原文,如果數據庫的信息泄露后就會造成用戶信息的泄露。通過一定的規則將密碼轉換為密文,即使數據庫中的數據泄露也不會造成用戶信息的泄露
注冊的時候對密碼進行加密,登錄的時候也需要進行加密,加密后用加密后的密碼是不能登錄的,只要加密規則不泄露就能保證用戶信息的安全
(2)加密規則
加密規則可以自定義,在項目開發中通常使用BASE64和MD5編碼方式:
BASE64:可以反編碼的編碼方式,明文可以變為密文、密文可以變為明文
MD5:不可逆的編碼方式,只能明文變密文,密碼丟失只能重置不能獲取原密碼(非對稱)
(3)加鹽
隨機生成一個字符串與明文進行拼接,用拼接后的字符串進行加密,可以防止暴力破解的方式通過密文獲取到明文
再加鹽后破解到的明文含有添加的部分,並不是真實的用戶的密碼
2、加密
(1)書寫配置類
定義加密規則:
@Bean public HashedCredentialsMatcher getHashedCredentialsMatcher(){ HashedCredentialsMatcher matcher=new HashedCredentialsMatcher(); matcher.setHashAlgorithmName("md5"); //加密次數,要注意的是這里的次數要與注冊的時候加密的次數保持一致 matcher.setHashIterations(1); return matcher; }
把matcher給realm,matcher是用來指定加密規則的
@Bean//realm public MyRealm getMyRealm(HashedCredentialsMatcher matcher) { MyRealm myRealm = new MyRealm(); myRealm.setCredentialsMatcher(matcher); return myRealm; }
(2)定義一個注冊頁面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>regist</title> </head> <body> <form action="/user/regist" method="post"> <p>用戶名:<input type="text" name="username"></p> <p>密碼 :<input type="password" name="password"></p> <p><input type="submit" value="提交"></p> </form> </body> </html>
(3)書寫controller模擬注冊過程,獲取到加密后的密碼
@PostMapping("regist") public String regist(String username,String password){ System.out.println("zhuce"); System.out.println(password); Md5Hash md5Hash=new Md5Hash(password); System.out.println(md5Hash.toHex()); return "login"; }
(4)測試

控制台打印密文:
zhuce 123456 e10adc3949ba59abbe56e057f20f883e
3、加鹽加密
@PostMapping("regist") public String regist(String username,String password){ System.out.println("zhuce"); System.out.println(password); Md5Hash md5Hash=new Md5Hash(password); System.out.println("加密"+md5Hash.toHex()); //加鹽加密 String num=(new Random().nextInt(90000)+10000)+""; Md5Hash md5Hash1=new Md5Hash(password,num); System.out.println("加鹽加密"+md5Hash1); //加鹽加密多次 Md5Hash md5Hash2=new Md5Hash(password,num,3); System.out.println("加鹽加密三次:"+md5Hash2); return "login"; }
測試結果:
zhuce 123456 加密e10adc3949ba59abbe56e057f20f883e 加鹽加密af45127dce6104313955527666e53d75 加鹽加密三次:cc9f07e0574e6e41c99556d1f13e675d
要注意加鹽的鹽要轉換為字符串形式的
4、模擬加鹽加密后的登錄過程
(1)訪問controller,生成加鹽加密后的密碼與鹽,並手動寫入到數據庫中
@PostMapping("regist") public String regist(String username,String password){ System.out.println("zhuce"); System.out.println("密碼"+password); //加鹽加密 String num=(new Random().nextInt(90000)+10000)+""; System.out.println("鹽:"+num); Md5Hash md5Hash1=new Md5Hash(password,num); System.out.println("加鹽加密"+md5Hash1); return "login"; }
生成加密后的密碼:
zhuce 密碼123 鹽:68795 加鹽加密ae1de49a9f24d38da38f7afe9ce70db4
zhuce 密碼123 鹽:42871 加鹽加密ecdcbc643a41257ee89c81c5e7a2843d
兩次輸入的密碼雖然是一樣的,但是生成的加密后的密碼並不相同,原因是密碼是加鹽后進行加密的
(2)將加密后的密碼與鹽寫入到數據庫

(3)修改自定義realm中的代碼
@Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { //參數authenticationToken就是傳遞的subject.login(token)中的參數 UsernamePasswordToken token= (UsernamePasswordToken) authenticationToken; //從token中獲取用戶名 String username=token.getUsername(); User user= userDao.getUserByUsername(username); if(user==null){ return null; } AuthenticationInfo info=new SimpleAuthenticationInfo( username,//當前用戶用戶名,跟上面的doGetAuthorizationInfo方法是對應的 user.getUserPwd(),//從數據庫查詢出來的安全密碼 ByteSource.Util.bytes(user.getPwdSalt()),//用戶的密碼是加了鹽的 getName()); return info; }
因為密碼是加了鹽的,因此要對認證器進行修改
(4)測試

