加盐的目是:
即使数据被拖库,攻击者也无法从中破解出用户的密码。
即使数据被拖库,攻击者也无法伪造登录请求通过验证。
即使数据被拖库,攻击者劫持了用户的请求数据,也无法破解出用户的密码。
思路:
1.先得到用户的账号和密码
String username = request.getParameter("username");//接受用户账号
String password = request.getParameter("password");//接受用户密码
2.在得到的账号中去数据库里查询是否存在
3.账号存在,取出数据库里加盐的字段和密码
![]()
ps:这里取出来的密码是之前注册的时候已经加盐好了
4.把用户的密码md5一下拼接加盐后,在md5一下!
5.最后在颁发身份令牌
登录代码
package spring_servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.auth0.jwt.interfaces.DecodedJWT;
import net.sf.json.JSONObject;
import springDao.BaseController;
import springEntity.mt_admin;
import spring_service.mt_adminService;
public class mt_adminServlet extends HttpServlet {
private BaseController cont = new BaseController();
/*
* Get请求
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out = response.getWriter();
request.setCharacterEncoding("utf-8");// 设置中文
response.setContentType("text/html;charset=utf-8");// 设置中文
String action = request.getParameter("op");// 获取页面中op对象
if ("login".equals(action)) {
login(request, response);
} else if ("test".equals(action)) {
Test(request, response);
} else {
out.print("参数错误");
}
}
/*
* 登录
* @param username用户名
* @param password密码
*/
private void login(HttpServletRequest request, HttpServletResponse response) throws IOException {
PrintWriter out = response.getWriter();
String username = request.getParameter("username");// GET或POST都可得到参数
String password = request.getParameter("password");
if (username == null || password == null) {
out.print("{'error':-3,'message':'参数错误'}");
return;
}
mt_adminService AdminService = new mt_adminService();
mt_admin admin = AdminService.getAdmin(username);// 调用mt_adminService里getAdmin的方法
if (admin == null) {
out.print("{'error':-1,'message':'账号不存在'}");
return;
}
//公共类
String Md = cont.getMD5(cont.getMD5(password) + admin.getSalt());// 原密码加盐在md5
if (!Md.equals(admin.getPassword())) {// 对比枚举后的密码是否和数据库的密码相同
out.print("{'error':-1,'message':'密码错误'}");
return;
}
//颁发身份令牌
String jwt = cont.HS256(admin.getToken());
String xiaozhang = "{'username':'" + admin.getUsername() + "','jwt':'" + jwt + "'}";
Cookie cookie = new Cookie("xiaozhang", xiaozhang);
cookie.setMaxAge(60*60);// 设置其1小时的生命周期 设置 0是删除cookie
cookie.setPath("/");// 设置cookie的路径
response.addCookie(cookie);// 添加cookie
out.print("{'error':0,'message':'登录成功'}");//网页端输出
System.err.println("登录成功");// 控制台输出
}
/*
* 测试有没有登录过
*/
private void Test(HttpServletRequest request, HttpServletResponse response) throws IOException {
PrintWriter out = response.getWriter();
Cookie[] AdminCookie = request.getCookies();// 获取当前cookie
JSONObject strJson = null;
// 如果没有任何的Cookie
if (AdminCookie == null) {
out.print("{'error':-2,'message':'未登录'}");
return;
}
// 循环所有Cookie找出里面是否有名为xiaozhang的Cookie
for (Cookie val : AdminCookie) {
if (val.getName().equals("xiaozhang")) {
strJson = JSONObject.fromObject(val.getValue());// 转成json
}
}
// 找不到xiaozhang的Cookie
if (strJson == null) {
out.print("{'error':-2,'message':'未登录'}");
return;
}
mt_adminService AdminService = new mt_adminService();
mt_admin admin = AdminService.getAdmin(strJson.getString("username"));
if (admin == null) {// 找不到该用户
out.print("{'error':-3,'message':'登录过期,请重新登录'}");
return;
}
// 验证身份
DecodedJWT jwt = cont.JHS256(admin.getToken(), strJson.getString("jwt"));
if (jwt == null) {// 身份令牌不匹配
out.print("{'error':-3,'message':'登录过期,请重新登录'}");
return;
}
out.print("{'error':0,'message':'登录成功'}");
System.err.println("{'error':0,'message':'登录成功'}");
}
/*
* Post提交
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);// 转到GET提交里去
}
}
把公共类的代码贴出来
package springDao;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.util.Date;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
//常用的参数
public class BaseController {
/**
* 对字符串md5加密(小写+字母)
*
* @param str 传入要加密的字符串
* @return MD5加密后的字符串
*/
public static String getMD5(String str) {
try {
// 生成一个MD5加密计算摘要
MessageDigest md = MessageDigest.getInstance("MD5");
// 计算md5函数
md.update(str.getBytes());
// digest()最后确定返回md5 hash值,返回值为8为字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符
// BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值
return new BigInteger(1, md.digest()).toString(16);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 生成随机数
*
*/
public static String makeOrderNums(){
String datenum="";
datenum=DateUtils.getStrByDate(new Date(),"yyyMMddHHmmss");
String num=""+ (int)(Math.random()*10)+(int)(Math.random()*10)+(int)(Math.random()*10)+(int)(Math.random()*10);
return datenum+num;
}
/**
* Example using HS256算法
* @param secret 保存的秘密
*/
public static String HS256(String id){
String token =null;
try {
Algorithm algorithm = Algorithm.HMAC256(id);//唯一id
token = JWT.create()
.withIssuer("auth0")
.sign(algorithm);
} catch (UnsupportedEncodingException exception){
//不支持UTF-8
} catch (JWTCreationException exception){
//Invalid Signing configuration / Couldn't convert Claims.
}
return token;
}
/**
* Example using HS256解法
* @param token HS256算法加密后的字符串
* jwt 返回为null者说明身份验证失败
*/
public static DecodedJWT JHS256(String id,String token){
DecodedJWT jwt = null;
try {
Algorithm algorithm = Algorithm.HMAC256(id);//唯一id
JWTVerifier verifier = JWT.require(algorithm)
.withIssuer("auth0")
.build(); //Reusable verifier instance
jwt = verifier.verify(token);
} catch (UnsupportedEncodingException exception){
//UTF-8 encoding not supported
} catch (JWTVerificationException exception){
//Invalid signature/claims
}
return jwt;
}
}