SpringBoot+随机盐值+双重MD5实现加密登录

🏡浩泽学编程个人主页
🔥 推荐专栏《深入浅出SpringBoot》《java对AI的调用开发》
《RabbitMQ》《Spring》《SpringMVC》

🛸学无止境,不骄不躁,知行合一

文章目录


前言

SpringBoot+随机盐值+双重MD5实现加密登录。


一、salt和MD5

简单认识

加盐(盐英文就是salt) :在密码学中,是指通过在密码任意固定位置插入特定的字符串 ,让散列后的结果和使用原始密码的散列结果不相符,这种过程称之为"加盐"。
MD5信息摘要算法(英语:MD5 Message-Digest Algorithm) :一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。MD5由美国密码学家罗纳德·李维斯特(Ronald Linn Rivest)设计,于1992年公开,用以取代MD4算法。这套算法的程序在 RFC 1321 标准中被加以规范。1996年后该算法被证实存在弱点,可以被加以破解,对于需要高度安全性的数据,专家一般建议改用其他算法,如SHA-2。2004年,证实MD5算法无法防止碰撞(collision),因此不适用于安全性认证,如SSL公开密钥认证或是数字签名等用途。
MD5原理:MD5码以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。

说到这里,细心的朋友可以发现,你这不是说MD5可以被破解,存在弱点,现在的MD5破解工具也很多,你为什么还在使用呢。其实作为初学者,我们是一步步接触更好的技术,我也是在接触好技术的过程,对项目加密等问题也在不断完善,这是我学习过程使用到的加密技术,所以在此记录分享一下。并且随机盐与MD5融合破解难度大大增加,很难。

如何使用

两次MD5加密

  • 用户端:PASS = MD5(明文,就是用户输入的密码;明文+固定Salt)
    • 第一次MD5加密:前端传给后端时候,进行第一次MD5加密,防止密码在网络中以明文传输。
  • 服务端:PASS = MD5(用户端PASS,就是前端加密后的密码;前端PASS+随机Salt)
    • 第二次MD5加密:服务器端(后端)接收到MD5加密后的密码存入数据库之前进行第二次MD5加密。
    • 这次加密采用的是随机生成盐值,然后与密码拼接,进行MD5加密,再将随机生成的盐值混合(按照自己设置的规律)到加密后的密码中存入数据库,这样就不会存在盐值随机造成的自己无法破解。

二、具体实现

前端

引入MD5的js文件

md5.min.js:直接给大家,节省大家寻找的时间,文件取名相同,复制粘贴即可。

js 复制代码
/**
 * [js-md5]{@link https://github.com/emn178/js-md5}
 *
 * @namespace md5
 * @version 0.7.2
 */
!function(){"use strict";function Md5(t){if(t)blocks[0]=blocks[16]=blocks[1]=blocks[2]=blocks[3]=blocks[4]=blocks[5]=blocks[6]=blocks[7]=blocks[8]=blocks[9]=blocks[10]=blocks[11]=blocks[12]=blocks[13]=blocks[14]=blocks[15]=0,this.blocks=blocks,this.buffer8=buffer8;else if(ARRAY_BUFFER){var r=new ArrayBuffer(68);this.buffer8=new Uint8Array(r),this.blocks=new Uint32Array(r)}else this.blocks=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];this.h0=this.h1=this.h2=this.h3=this.start=this.bytes=this.hBytes=0,this.finalized=this.hashed=!1,this.first=!0}var ERROR="input is invalid type",WINDOW="object"==typeof window,root=WINDOW?window:{};root.JS_MD5_NO_WINDOW&&(WINDOW=!1);var WEB_WORKER=!WINDOW&&"object"==typeof self,NODE_JS=!root.JS_MD5_NO_NODE_JS&&"object"==typeof process&&process.versions&&process.versions.node;NODE_JS?root=global:WEB_WORKER&&(root=self);var COMMON_JS=!root.JS_MD5_NO_COMMON_JS&&"object"==typeof module&&module.exports,AMD="function"==typeof define&&define.amd,ARRAY_BUFFER=!root.JS_MD5_NO_ARRAY_BUFFER&&"undefined"!=typeof ArrayBuffer,HEX_CHARS="0123456789abcdef".split(""),EXTRA=[128,32768,8388608,-2147483648],SHIFT=[0,8,16,24],OUTPUT_TYPES=["hex","array","digest","buffer","arrayBuffer","base64"],BASE64_ENCODE_CHAR="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split(""),blocks=[],buffer8;if(ARRAY_BUFFER){var buffer=new ArrayBuffer(68);buffer8=new Uint8Array(buffer),blocks=new Uint32Array(buffer)}(root.JS_MD5_NO_NODE_JS||!Array.isArray)&&(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),!ARRAY_BUFFER||!root.JS_MD5_NO_ARRAY_BUFFER_IS_VIEW&&ArrayBuffer.isView||(ArrayBuffer.isView=function(t){return"object"==typeof t&&t.buffer&&t.buffer.constructor===ArrayBuffer});var createOutputMethod=function(t){return function(r){return new Md5(!0).update(r)[t]()}},createMethod=function(){var t=createOutputMethod("hex");NODE_JS&&(t=nodeWrap(t)),t.create=function(){return new Md5},t.update=function(r){return t.create().update(r)};for(var r=0;r<OUTPUT_TYPES.length;++r){var e=OUTPUT_TYPES[r];t[e]=createOutputMethod(e)}return t},nodeWrap=function(method){var crypto=eval("require('crypto')"),Buffer=eval("require('buffer').Buffer"),nodeMethod=function(t){if("string"==typeof t)return crypto.createHash("md5").update(t,"utf8").digest("hex");if(null===t||void 0===t)throw ERROR;return t.constructor===ArrayBuffer&&(t=new Uint8Array(t)),Array.isArray(t)||ArrayBuffer.isView(t)||t.constructor===Buffer?crypto.createHash("md5").update(new Buffer(t)).digest("hex"):method(t)};return nodeMethod};Md5.prototype.update=function(t){if(!this.finalized){var r,e=typeof t;if("string"!==e){if("object"!==e)throw ERROR;if(null===t)throw ERROR;if(ARRAY_BUFFER&&t.constructor===ArrayBuffer)t=new Uint8Array(t);else if(!(Array.isArray(t)||ARRAY_BUFFER&&ArrayBuffer.isView(t)))throw ERROR;r=!0}for(var s,i,o=0,h=t.length,f=this.blocks,a=this.buffer8;h>o;){if(this.hashed&&(this.hashed=!1,f[0]=f[16],f[16]=f[1]=f[2]=f[3]=f[4]=f[5]=f[6]=f[7]=f[8]=f[9]=f[10]=f[11]=f[12]=f[13]=f[14]=f[15]=0),r)if(ARRAY_BUFFER)for(i=this.start;h>o&&64>i;++o)a[i++]=t[o];else for(i=this.start;h>o&&64>i;++o)f[i>>2]|=t[o]<<SHIFT[3&i++];else if(ARRAY_BUFFER)for(i=this.start;h>o&&64>i;++o)s=t.charCodeAt(o),128>s?a[i++]=s:2048>s?(a[i++]=192|s>>6,a[i++]=128|63&s):55296>s||s>=57344?(a[i++]=224|s>>12,a[i++]=128|s>>6&63,a[i++]=128|63&s):(s=65536+((1023&s)<<10|1023&t.charCodeAt(++o)),a[i++]=240|s>>18,a[i++]=128|s>>12&63,a[i++]=128|s>>6&63,a[i++]=128|63&s);else for(i=this.start;h>o&&64>i;++o)s=t.charCodeAt(o),128>s?f[i>>2]|=s<<SHIFT[3&i++]:2048>s?(f[i>>2]|=(192|s>>6)<<SHIFT[3&i++],f[i>>2]|=(128|63&s)<<SHIFT[3&i++]):55296>s||s>=57344?(f[i>>2]|=(224|s>>12)<<SHIFT[3&i++],f[i>>2]|=(128|s>>6&63)<<SHIFT[3&i++],f[i>>2]|=(128|63&s)<<SHIFT[3&i++]):(s=65536+((1023&s)<<10|1023&t.charCodeAt(++o)),f[i>>2]|=(240|s>>18)<<SHIFT[3&i++],f[i>>2]|=(128|s>>12&63)<<SHIFT[3&i++],f[i>>2]|=(128|s>>6&63)<<SHIFT[3&i++],f[i>>2]|=(128|63&s)<<SHIFT[3&i++]);this.lastByteIndex=i,this.bytes+=i-this.start,i>=64?(this.start=i-64,this.hash(),this.hashed=!0):this.start=i}return this.bytes>4294967295&&(this.hBytes+=this.bytes/4294967296<<0,this.bytes=this.bytes%4294967296),this}},Md5.prototype.finalize=function(){if(!this.finalized){this.finalized=!0;var t=this.blocks,r=this.lastByteIndex;t[r>>2]|=EXTRA[3&r],r>=56&&(this.hashed||this.hash(),t[0]=t[16],t[16]=t[1]=t[2]=t[3]=t[4]=t[5]=t[6]=t[7]=t[8]=t[9]=t[10]=t[11]=t[12]=t[13]=t[14]=t[15]=0),t[14]=this.bytes<<3,t[15]=this.hBytes<<3|this.bytes>>29,this.hash()}},Md5.prototype.hash=function(){var t,r,e,s,i,o,h=this.blocks;this.first?(t=h[0]-680876937,t=(t<<7|t>>>25)-271733879<<0,s=(-1732584194^2004318071&t)+h[1]-117830708,s=(s<<12|s>>>20)+t<<0,e=(-271733879^s&(-271733879^t))+h[2]-1126478375,e=(e<<17|e>>>15)+s<<0,r=(t^e&(s^t))+h[3]-1316259209,r=(r<<22|r>>>10)+e<<0):(t=this.h0,r=this.h1,e=this.h2,s=this.h3,t+=(s^r&(e^s))+h[0]-680876936,t=(t<<7|t>>>25)+r<<0,s+=(e^t&(r^e))+h[1]-389564586,s=(s<<12|s>>>20)+t<<0,e+=(r^s&(t^r))+h[2]+606105819,e=(e<<17|e>>>15)+s<<0,r+=(t^e&(s^t))+h[3]-1044525330,r=(r<<22|r>>>10)+e<<0),t+=(s^r&(e^s))+h[4]-176418897,t=(t<<7|t>>>25)+r<<0,s+=(e^t&(r^e))+h[5]+1200080426,s=(s<<12|s>>>20)+t<<0,e+=(r^s&(t^r))+h[6]-1473231341,e=(e<<17|e>>>15)+s<<0,r+=(t^e&(s^t))+h[7]-45705983,r=(r<<22|r>>>10)+e<<0,t+=(s^r&(e^s))+h[8]+1770035416,t=(t<<7|t>>>25)+r<<0,s+=(e^t&(r^e))+h[9]-1958414417,s=(s<<12|s>>>20)+t<<0,e+=(r^s&(t^r))+h[10]-42063,e=(e<<17|e>>>15)+s<<0,r+=(t^e&(s^t))+h[11]-1990404162,r=(r<<22|r>>>10)+e<<0,t+=(s^r&(e^s))+h[12]+1804603682,t=(t<<7|t>>>25)+r<<0,s+=(e^t&(r^e))+h[13]-40341101,s=(s<<12|s>>>20)+t<<0,e+=(r^s&(t^r))+h[14]-1502002290,e=(e<<17|e>>>15)+s<<0,r+=(t^e&(s^t))+h[15]+1236535329,r=(r<<22|r>>>10)+e<<0,t+=(e^s&(r^e))+h[1]-165796510,t=(t<<5|t>>>27)+r<<0,s+=(r^e&(t^r))+h[6]-1069501632,s=(s<<9|s>>>23)+t<<0,e+=(t^r&(s^t))+h[11]+643717713,e=(e<<14|e>>>18)+s<<0,r+=(s^t&(e^s))+h[0]-373897302,r=(r<<20|r>>>12)+e<<0,t+=(e^s&(r^e))+h[5]-701558691,t=(t<<5|t>>>27)+r<<0,s+=(r^e&(t^r))+h[10]+38016083,s=(s<<9|s>>>23)+t<<0,e+=(t^r&(s^t))+h[15]-660478335,e=(e<<14|e>>>18)+s<<0,r+=(s^t&(e^s))+h[4]-405537848,r=(r<<20|r>>>12)+e<<0,t+=(e^s&(r^e))+h[9]+568446438,t=(t<<5|t>>>27)+r<<0,s+=(r^e&(t^r))+h[14]-1019803690,s=(s<<9|s>>>23)+t<<0,e+=(t^r&(s^t))+h[3]-187363961,e=(e<<14|e>>>18)+s<<0,r+=(s^t&(e^s))+h[8]+1163531501,r=(r<<20|r>>>12)+e<<0,t+=(e^s&(r^e))+h[13]-1444681467,t=(t<<5|t>>>27)+r<<0,s+=(r^e&(t^r))+h[2]-51403784,s=(s<<9|s>>>23)+t<<0,e+=(t^r&(s^t))+h[7]+1735328473,e=(e<<14|e>>>18)+s<<0,r+=(s^t&(e^s))+h[12]-1926607734,r=(r<<20|r>>>12)+e<<0,i=r^e,t+=(i^s)+h[5]-378558,t=(t<<4|t>>>28)+r<<0,s+=(i^t)+h[8]-2022574463,s=(s<<11|s>>>21)+t<<0,o=s^t,e+=(o^r)+h[11]+1839030562,e=(e<<16|e>>>16)+s<<0,r+=(o^e)+h[14]-35309556,r=(r<<23|r>>>9)+e<<0,i=r^e,t+=(i^s)+h[1]-1530992060,t=(t<<4|t>>>28)+r<<0,s+=(i^t)+h[4]+1272893353,s=(s<<11|s>>>21)+t<<0,o=s^t,e+=(o^r)+h[7]-155497632,e=(e<<16|e>>>16)+s<<0,r+=(o^e)+h[10]-1094730640,r=(r<<23|r>>>9)+e<<0,i=r^e,t+=(i^s)+h[13]+681279174,t=(t<<4|t>>>28)+r<<0,s+=(i^t)+h[0]-358537222,s=(s<<11|s>>>21)+t<<0,o=s^t,e+=(o^r)+h[3]-722521979,e=(e<<16|e>>>16)+s<<0,r+=(o^e)+h[6]+76029189,r=(r<<23|r>>>9)+e<<0,i=r^e,t+=(i^s)+h[9]-640364487,t=(t<<4|t>>>28)+r<<0,s+=(i^t)+h[12]-421815835,s=(s<<11|s>>>21)+t<<0,o=s^t,e+=(o^r)+h[15]+530742520,e=(e<<16|e>>>16)+s<<0,r+=(o^e)+h[2]-995338651,r=(r<<23|r>>>9)+e<<0,t+=(e^(r|~s))+h[0]-198630844,t=(t<<6|t>>>26)+r<<0,s+=(r^(t|~e))+h[7]+1126891415,s=(s<<10|s>>>22)+t<<0,e+=(t^(s|~r))+h[14]-1416354905,e=(e<<15|e>>>17)+s<<0,r+=(s^(e|~t))+h[5]-57434055,r=(r<<21|r>>>11)+e<<0,t+=(e^(r|~s))+h[12]+1700485571,t=(t<<6|t>>>26)+r<<0,s+=(r^(t|~e))+h[3]-1894986606,s=(s<<10|s>>>22)+t<<0,e+=(t^(s|~r))+h[10]-1051523,e=(e<<15|e>>>17)+s<<0,r+=(s^(e|~t))+h[1]-2054922799,r=(r<<21|r>>>11)+e<<0,t+=(e^(r|~s))+h[8]+1873313359,t=(t<<6|t>>>26)+r<<0,s+=(r^(t|~e))+h[15]-30611744,s=(s<<10|s>>>22)+t<<0,e+=(t^(s|~r))+h[6]-1560198380,e=(e<<15|e>>>17)+s<<0,r+=(s^(e|~t))+h[13]+1309151649,r=(r<<21|r>>>11)+e<<0,t+=(e^(r|~s))+h[4]-145523070,t=(t<<6|t>>>26)+r<<0,s+=(r^(t|~e))+h[11]-1120210379,s=(s<<10|s>>>22)+t<<0,e+=(t^(s|~r))+h[2]+718787259,e=(e<<15|e>>>17)+s<<0,r+=(s^(e|~t))+h[9]-343485551,r=(r<<21|r>>>11)+e<<0,this.first?(this.h0=t+1732584193<<0,this.h1=r-271733879<<0,this.h2=e-1732584194<<0,this.h3=s+271733878<<0,this.first=!1):(this.h0=this.h0+t<<0,this.h1=this.h1+r<<0,this.h2=this.h2+e<<0,this.h3=this.h3+s<<0)},Md5.prototype.hex=function(){this.finalize();var t=this.h0,r=this.h1,e=this.h2,s=this.h3;return HEX_CHARS[t>>4&15]+HEX_CHARS[15&t]+HEX_CHARS[t>>12&15]+HEX_CHARS[t>>8&15]+HEX_CHARS[t>>20&15]+HEX_CHARS[t>>16&15]+HEX_CHARS[t>>28&15]+HEX_CHARS[t>>24&15]+HEX_CHARS[r>>4&15]+HEX_CHARS[15&r]+HEX_CHARS[r>>12&15]+HEX_CHARS[r>>8&15]+HEX_CHARS[r>>20&15]+HEX_CHARS[r>>16&15]+HEX_CHARS[r>>28&15]+HEX_CHARS[r>>24&15]+HEX_CHARS[e>>4&15]+HEX_CHARS[15&e]+HEX_CHARS[e>>12&15]+HEX_CHARS[e>>8&15]+HEX_CHARS[e>>20&15]+HEX_CHARS[e>>16&15]+HEX_CHARS[e>>28&15]+HEX_CHARS[e>>24&15]+HEX_CHARS[s>>4&15]+HEX_CHARS[15&s]+HEX_CHARS[s>>12&15]+HEX_CHARS[s>>8&15]+HEX_CHARS[s>>20&15]+HEX_CHARS[s>>16&15]+HEX_CHARS[s>>28&15]+HEX_CHARS[s>>24&15]},Md5.prototype.toString=Md5.prototype.hex,Md5.prototype.digest=function(){this.finalize();var t=this.h0,r=this.h1,e=this.h2,s=this.h3;return[255&t,t>>8&255,t>>16&255,t>>24&255,255&r,r>>8&255,r>>16&255,r>>24&255,255&e,e>>8&255,e>>16&255,e>>24&255,255&s,s>>8&255,s>>16&255,s>>24&255]},Md5.prototype.array=Md5.prototype.digest,Md5.prototype.arrayBuffer=function(){this.finalize();var t=new ArrayBuffer(16),r=new Uint32Array(t);return r[0]=this.h0,r[1]=this.h1,r[2]=this.h2,r[3]=this.h3,t},Md5.prototype.buffer=Md5.prototype.arrayBuffer,Md5.prototype.base64=function(){for(var t,r,e,s="",i=this.array(),o=0;15>o;)t=i[o++],r=i[o++],e=i[o++],s+=BASE64_ENCODE_CHAR[t>>>2]+BASE64_ENCODE_CHAR[63&(t<<4|r>>>4)]+BASE64_ENCODE_CHAR[63&(r<<2|e>>>6)]+BASE64_ENCODE_CHAR[63&e];return t=i[o],s+=BASE64_ENCODE_CHAR[t>>>2]+BASE64_ENCODE_CHAR[t<<4&63]+"=="};var exports=createMethod();COMMON_JS?module.exports=exports:(root.md5=exports,AMD&&define(function(){return exports}))}();
  • 登录页面。
  • 其他样式及其他js文件不再给,大家只需要关注手机号和密码输入框,还有提交按钮就行,主要在于实现登录。
  • 解释一下下面代码主要含义:登录按钮绑定login函数,在该函数中调用了dologin函数,dologin中获取输入框输入密码,然后取出盐值的其中4个字符串然后混合拼接到密码中,然后使用MD5加密。最后使用ajax,将加密后的密码封装到参数中。这样传输过程就不再是明文形式。而ajax是服务器端进行路径控制层拦截处理

login.html:

html 复制代码
<!DOCTYPE html>
<html lang="en"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
    <!-- jquery -->
    <script type="text/javascript" th:src="@{/js/jquery.min.js}"></script>
    <!-- bootstrap -->
    <link rel="stylesheet" type="text/css" th:href="@{/bootstrap/css/bootstrap.min.css}"/>
    <script type="text/javascript" th:src="@{/bootstrap/js/bootstrap.min.js}"></script>
    <!-- jquery-validator -->
    <script type="text/javascript" th:src="@{/jquery-validation/jquery.validate.min.js}"></script>
    <script type="text/javascript" th:src="@{/jquery-validation/localization/messages_zh.min.js}"></script>
    <!-- md5.js -->
    <script type="text/javascript" th:src="@{/js/md5.min.js}"></script>
    <!-- common.js -->
    <script type="text/javascript" th:src="@{/js/common.js}"></script>
</head>
<body>
<form name="loginForm" id="loginForm" method="post" style="width:50%; margin:0 auto">

    <h2 style="text-align:center; margin-bottom: 20px">用户登录</h2>

    <div class="form-group">
        <div class="row">
            <label class="form-label col-md-4">请输入手机号码</label>
            <div class="col-md-5">
                <input id="mobile" minlength="11" maxlength="11" name="mobile" class="form-control" type="text" placeholder="手机号码" required="true"/>
            </div>
        </div>
    </div>

    <div class="form-group">
        <div class="row">
            <label class="form-label col-md-4">请输入密码</label>
            <div class="col-md-5">
                <input id="password" name="password" class="form-control" type="password" placeholder="密码" required="true" />
            </div>
        </div>
    </div>

    <div class="row">
        <div class="col-md-5">
            <button class="btn btn-primary btn-block" type="reset" onclick="reset()">重置</button>
        </div>
        <div class="col-md-5">
            <button class="btn btn-primary btn-block" type="submit" onclick="login()">登录</button>
        </div>
    </div>
</form>
</body>
<script>
    function login() {
        $("#loginForm").validate({
            submitHandler: function (form) {
                doLogin();
            }
        });
    }

    function doLogin() {
        var inputPass = $("#password").val();
        var salt = "1a2b3c4d";
        var str = "" + salt.charAt(0) + salt.charAt(2) + inputPass + salt.charAt(5) + salt.charAt(4);
        var password = md5(str);

        $.ajax({
            url: "/login/doLogin",
            type: "POST",
            data: {
                mobile: $("#mobile").val(),
                password: password
            },
            success: function (data) {
                layer.closeAll();
                if (data.code == 200) {
                    layer.msg("成功");
                    console.log(data);
                    document.cookie = "userTicket=" + data.object;
                    window.location.href = "/goods/toList";
                } else {
                    layer.msg(data.message);
                }
            },
            error: function () {
                layer.closeAll();
            }
        });
    }
</script>
</html>

服务器端(后端)

引入依赖:

xml 复制代码
<dependency>
	<groupId>commons-codec</groupId>
	<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
	<groupId>org.apache.commons</groupId>
	<artifactId>commons-lang3</artifactId>
	<version>3.12.0</version>
</dependency>
  • 封装MD5加密解密工具类
  • 解释一下如下代码:首先加密函数是随机生成一个16位盐值,然后与传过来的密码拼接,拼接后进行MD5加密,这个盐值,我们必须要保存的,要不然我们自己也无法解密,所以再将盐值按照自定义的方法插入加密后的密文中。然后在解密时,根据这个方法取出盐值,进行解密操作。
java 复制代码
public class MD5Util {

	public static String md5(String str){
        return DigestUtils.md5Hex(str);
    }

    /**
     * 加密
     * 生成盐和加盐后的MD5码,并将盐混入到MD5码中,对MD5密码进行加强
     **/
    public static String generateSaltPassword(String password) {
        Random random = new Random();
        
        /**
         * 生成一个16位的随机数,也就是盐
         **/
        StringBuilder stringBuilder = new StringBuilder(16);
        stringBuilder.append(random.nextInt(99999999)).append(random.nextInt(99999999));
        int len = stringBuilder.length();
        if (len < 16) {
            for (int i = 0; i < 16 - len; i++) {
                stringBuilder.append("0");
            }
        }
        // 生成盐
        String salt = stringBuilder.toString();
        //将盐加到明文中,并生成新的MD5码
        password = md5(password + salt);
        //将盐混到新生成的MD5码中,之所以这样做是为了后期解密,校验密码
        char[] cs = new char[48];
        for (int i = 0; i < 48; i += 3) {
            cs[i] = password.charAt(i / 3 * 2);
            char c = salt.charAt(i / 3);
            cs[i + 1] = c;
            cs[i + 2] = password.charAt(i / 3 * 2 + 1);
        }
        return new String(cs);
    }

    /**
     * 解密
     * 将混入MD5加密的密文中的盐取出来,然后将传来的密码按照此盐进行MD5加密,再比较
     **/
    public static boolean verifySaltPassword(String password, String md) {
        //先从MD5码中取出之前加的盐和加盐后生成的MD5码
        char[] cs1 = new char[32];
        char[] cs2 = new char[16];
        for (int i = 0; i < 48; i += 3) {
            cs1[i / 3 * 2] = md.charAt(i);
            cs1[i / 3 * 2 + 1] = md.charAt(i + 2);
            cs2[i / 3] = md.charAt(i + 1);
        }
        String salt = new String(cs2);
        //比较二者是否相同
        return md5(password + salt).equals(new String(cs1));
    }
}

这里我准备了个测试:传过来个前端加密的密码,进行加密,再进行解密验证。

java 复制代码
    public static void main(String[] args) {
        String p1 = generateSaltPassword("d3b1294a61a07da9b49b6e22b2cbd7f9");
        System.out.println(p1);
        System.out.println(verifySaltPassword("d3b1294a61a07da9b49b6e22b2cbd7f9",p1));

    }

可以看到,解密加密成功。

登录逻辑处理,注重看登录逻辑,一些工具类不再列出。

java 复制代码
public RespBean doLogin(LoginVo loginVo, HttpServletRequest request, HttpServletResponse response) {
        String mobile = loginVo.getMobile();
        String password = loginVo.getPassword();
//        if (StringUtils.isEmpty(mobile) || StringUtils.isEmpty(password)) {
//            return RespBean.error(RespBeanEnum.LOGIN_ERROR);
//        }
//        if (!ValidatorUtil.isMobile(mobile)){
//            return RespBean.error(RespBeanEnum.MOBILE_ERROR);
//        }
        //根据手机号获取用户
        User user = userMapper.selectById(mobile);
        if (null == user) {
            throw new GlobalException(RespBeanEnum.LOGIN_ERROR);
        }
        // 获取数据库用户密码
        String saltPassword = user.getPassword();
        //判断密码是否正确
        if (!MD5Util.verifySaltPassword(password, saltPassword)){
            throw new GlobalException(RespBeanEnum.LOGIN_ERROR);
        }
        //生成cookie
        String ticket = UUIDUtil.uuid();
        redisTemplate.opsForValue().set("user:" + ticket,user);
//        request.getSession().setAttribute(ticket,user);
        CookieUtil.setCookie(request,response,"userTicker",ticket);
        return RespBean.success();
    }

补充

  • 随机盐的生成有很多方法,比如生成UUID截取等。
  • 如果想更加复杂可以将盐中的字符串按照一定自定义方法插入到传来的密码中,然后再MD5加密,最后再将盐值插入其中。

总结

以上就是我做项目使用的登录加密技术:随机盐值+MD5双重加密。

相关推荐
葫芦和十三4 小时前
图解 MongoDB 21|选举与 failover:Primary 是怎么选出来的
后端·mongodb·agent
GetcharZp4 小时前
26k Star 开源内网穿透神器 NetBird,一分钟实现全球设备互联!
后端
考虑考虑5 小时前
Mybatis实现批量插入
java·后端·mybatis
咖啡八杯5 小时前
GoF设计模式——中介者模式
java·后端·spring·设计模式
lizhongxuan8 小时前
多Agent之间的区别
后端
青石路9 小时前
记一次多JDK版本问题的排查,一坑套一坑,差点没爬上来
java
杨充10 小时前
1.面向对象设计思想
后端
IT_陈寒10 小时前
Java的Date类又坑了我一次,改用时间戳真香
前端·人工智能·后端
systemPro11 小时前
2.6亿条设备数据,历史查询从超时到50ms,我做了什么
后端
要阿尔卑斯吗11 小时前
提示词优化启示:为什么“按顺序输出“比“关键度评分“更有效
后端