目录
一、概念和理解
(一)MD5加密
(二)加密解密过程
(三)加盐
1.什么是盐值?
2.如何加盐?
二、手写加盐算法
(一)密码工具类
(二)项目改动
注册
登录
三、Spring Security 加盐和实现的实现步骤
(一)引入依赖
(二)排除 Spring Security 的自动注入
(三)实现加盐
密码组成
实现加盐
验证密码
一、概念和理解
(一)MD5加密
- MD5消息摘要算法,属Hash算法一类。
- MD5算法对输入任意长度的消息进行运行,产生一个128位的消息摘要(32位的数字字母混合码)。
- 特征:一对一、不可逆。
(二)加密解密过程
(三)加盐
1.什么是盐值?
- 盐值是指在密码哈希过程中,为了增强密码强度而添加的随机字符串。
- 通过将一个原始的密码与盐值结合起来进行哈希,以生成一个不可逆的密文,从而增加破解密码的困难度。
- 盐值通常被保存在数据库中,以便在验证用户的输入密码时使用。
2.如何加盐?
二、手写加盐算法
(一)密码工具类
package com.example.demo.common;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import java.util.UUID;
/**
* 关于密码的一个工具类
* 主要方法:
* 1.encrypt 给定明文 得到 数据库密码(创建账号存到数据库使用)
* 2.encrypt 给定明文和盐值 得到 数据库密码(校验密码使用)
* 3.verifyPassword 给定明文,校验是否正确
*/
public class PasswordUtils {
/**
* 加盐 并生成密码 --- 产生随机盐值进行加密
*
* @param password 用户输入的密码
* @return 数据库密码
*/
public static String encrypt(String password) {
if (!StringUtils.hasLength(password)) {
return null;
}
//1 产生 盐值
String salt = UUID.randomUUID().toString().replace("-", "");
//2 生成加盐 后的密码
String saltPassword = DigestUtils.md5DigestAsHex((salt + password).getBytes());
//3 数据库密码
return salt + "&" + saltPassword;
}
/**
* 给定盐值和密码,生成数据库
*
* @param password 用户输入的密码
* @param salt 盐值
* @return 数据库密码
*/
private static String encrypt(String password, String salt) {
if (!StringUtils.hasLength(password) || !StringUtils.hasLength(salt) || salt.length() != 32) {
return null;
}
//1 加密密码
String saltPassword = DigestUtils.md5DigestAsHex((salt + password).getBytes());
//2 数据库密码
return salt + "&" + saltPassword;
}
/**
* 校验密码
*
* @param inputPassword 用户输入的密码
* @param finalPassword 数据库密码
* @return 校验成功、校验失败
*/
public static boolean verifyPassword(String inputPassword, String finalPassword) {
if (!StringUtils.hasLength(inputPassword) || !StringUtils.hasLength(finalPassword) || finalPassword.length() != 65) {
return false;
}
String salt = finalPassword.substring(0, 32);
String finalPassword1 = encrypt(inputPassword, salt);
return finalPassword.equals(finalPassword1);
}
}
(二)项目改动
注册
@RequestMapping("/reg")
public AjaxResult reg(User user) {
//1.非空校验 和 参数有效性校验
if (user == null || !StringUtils.hasLength(user.getUsername()) || !StringUtils.hasLength(user.getPassword())) {
return AjaxResult.fail(400, "前端数据发送错误!");
}
//2.密码加盐处理
user.setPassword(PasswordUtils.encrypt(user.getPassword()));
return AjaxResult.success(200, "注册", userService.reg(user));
}
登录
@RequestMapping("/login")
public AjaxResult login(HttpServletRequest request, String username, String password) {
//1.非空校验
if (!StringUtils.hasLength(username) || !StringUtils.hasLength(password)) {
return AjaxResult.fail(400, "非法请求: 用户名或密码not Has Length");
}
//2.数据库查询
User user = userService.getUserByName(username);
if (user != null && user.getId() > 0) {
//但到这里说明存在这个用户,是还没判断密码是否ok
if (PasswordUtils.verifyPassword(password,user.getPassword())) {
//登陆成功:账号密码均正确
user.setPassword(null);//抹除敏感信息:返回前端数据之前抹除密码这个敏感信息
//3.将用户信息存储到 session
HttpSession session = request.getSession(true);
session.setAttribute(AppVariable.USER_SESSION_KEY, user);
return AjaxResult.success(200, "登陆成功", user);
}
}
return AjaxResult.success(400, "账号或密码不正确!", null);
}
三、Spring Security 加盐和实现的实现步骤
- Spring security是springboot官方提供的一种更加齐全的安全框架。(security -- 安全)
- Spring Security 的三大功能:授权、认证、安全相关的所有周边产品(比如加盐),其中 加密功能的思路 和我们手写的基本一致。
(一)引入依赖
可以使用Edit Starters插件,在pom.xml中直接按 alt + insert 即可,选择 spring security。或者使用下方的依赖复制粘贴进去也可。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
(二)排除 Spring Security 的自动注入
在启动类中DemoApplication中关闭自动注入
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
(三)实现加盐
密码组成
实现加盐
/**
* 加密
* @param password 用户输入的 明文
*/
String AddSalt(String password) {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String finalPassword = passwordEncoder.encode(password);//数据库密码
System.out.println(finalPassword);
return finalPassword;
}
验证密码
/**
* 验证密码
* @param password 用户输入的 明文
* @param finalPassword 数据库密码
*/
boolean Verify(String password,String finalPassword){
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
return passwordEncoder.matches(password,finalPassword);//使用passwordEncoder.matches对比即可
}