基于MD5算法对密码加密
MD5摘要算法
MD5信息摘要算法广泛使用的密码散列函数。
MD5可以产生出一个128位的散列值用于唯一标识源数据。
项目中通常使用MD5作为敏感数据的加密算法。
MD5特点
压缩性,MD5生成的摘要长度固定。
抗修改,源数据哪怕有个字节变化,MD5也会有巨大差异。
不可逆,无法通过MD5反向推算源数据。
Apache Commons Codec
Commons-Codec是Apache提供的编码/解码组件。
通过Commons-Codec可轻易生成源数据的MD5摘要。
MD5摘要方法:String md5 = DigestUtils.md5Hex(源数据)
引入MD5加密
在pom.xml中引入依赖
<!--MD5摘要工具包-->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.14</version>
</dependency>
并在com.ql.oa.utils包下创建MD5Utils.java工具类
package com.ql.oa.utils;
import org.apache.commons.codec.digest.DigestUtils;
public class MD5Utils {
/**
* 对源数据生成MD5摘要
* @param source 源数据
* @return MD5摘要
*/
public static String md5Digest(String source){
return DigestUtils.md5Hex(source);
}
}
敏感数据“加盐”混淆
在MD5Utils工具类中实现简单“加盐”加密方法:
/**
* 对源数据加盐混淆后生成MD5摘要
* @param source 源数据
* @param salt 盐值
* @return MD5摘要
*/
public static String md5Digest(String source , Integer salt){
//源数据混淆
char[] ca = source.toCharArray();//字符数组
for(int i = 0 ; i < ca.length ; i++){
ca[i] = (char)(ca[i] + salt);
}
String target = new String(ca);
// System.out.println(target);
String md5 = DigestUtils.md5Hex(target);
return md5;
}
打开数据库sys_user表,新增salt字段存盐值:
并把密码值和相应的盐值填上:
打开User.java实体类把salt属性加上
package com.ql.oa.entity;
public class User {
private Long userId;
private String username;
private String password;
private Long employeeId;
private Integer salt;
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Long getEmployeeId() {
return employeeId;
}
public void setEmployeeId(Long employeeId) {
this.employeeId = employeeId;
}
public Integer getSalt() {
return salt;
}
public void setSalt(Integer salt) {
this.salt = salt;
}
}
然后修改登录校验,打开UserService.java,修改checkLogin方法:
/**
* 根据前台输入进行登录校验
* @param username 前台输入的用户名
* @param password 前台输入的密码
* @return 校验通过后,包含对应用户数据的User实体类
* @throws BussinessException L001-用户名不存在,L002-密码错误
*/
public User checkLogin(String username, String password){
User user = userDao.selectByUsername(username);
if(user == null){
throw new BussinessException("L001", "用户名不存在");
}
//对前台输入的密码加盐混淆后生成MD5,与保存在数据库中的MD5密码进行比对
String md5 = MD5Utils.md5Digest(password, user.getSalt());
if(!md5.equals(user.getPassword())){
throw new BussinessException("L002", "密码错误");
}
return user;
}
运行项目登录测试成功跳转。
实现注销操作
在com.ql.oa.controller目录下创建LogoutServlet.java
package com.ql.oa.controller;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 注销功能
*/
@WebServlet(name = "LogoutServlet" , urlPatterns = "/logout")
public class LogoutServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//作废当前session
request.getSession().invalidate();
response.sendRedirect("/login.html");
}
}
然后修改index.ftl的注销标签访问地址
<!--注销按钮-->
<li class="layui-nav-item"><a href="/logout">注销</a></li>
运行项目测试注销成功注销后跳转到登录页。