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)测试