1.为什么需要对前端的数据进行加密
在实际业务当中,我们可能需要对一些敏感信息进行加密处理,比如用户名和密码,如果是明文传输的时候,极有可能被不法分子通过抓包的方式获取到账户信息,从而导致安全漏洞。基于上述的问题,可以有多种方式进行解决,比如说在客户端对账户信息进行加密处理,或者是通过更加可靠的协议HTTPS等。这里介绍通过加密的方式解决
2.为了更高的安全性,采用RSA算法进行加密
RSA又称为非对称加密,有着公钥和私钥之分,统称密钥对,由服务端颁发,然后将公钥给客户端,私钥存储在服务端,每次客户端在登录之前都要去获取公钥,每次的公钥都不一样,从而进一步提高安全性。
3.前端jsencrypt.js文件
网上有相当多的资源,这里就不放了
4.登录页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="encrypt.js"></script>
</head>
<body>
<form>
用户名:<input type="text" name="username" id="username">
密码: <input type="text" name="password" id="password">
<input type="button" onclick="getPublicKey()" value="获取公钥">
<input type="button" onclick="login()" value="登录"/>
</form>
<script>
function uuid() {
var temp_url = URL.createObjectURL(new Blob());
var uuid = temp_url.toString(); // blob:https://xxx.com/b250d159-e1b6-4a87-9002-885d90033be3
URL.revokeObjectURL(temp_url);
return uuid.substr(uuid.lastIndexOf("/") + 1);
}
var encrypt = new JSEncrypt();
function getPublicKey() {
$.ajax({
type: "GET",
url: "getPublicKey",
cache: false,
dataType: "json",
success: function (msg) {
encrypt.setPublicKey(msg.base64PublicKey);
localStorage.setItem("uuid", msg.uuid)
}
});
}
function login() {
let username = $("#username").val();
let password = $("#password").val();
encrUsername = encrypt.encrypt(username);
encrPassword = encrypt.encrypt(password);
const body = {
username: encrUsername,
password: encrPassword,
uuid: localStorage.getItem("uuid")
}
$.ajax({
type: "POST",
url: "login",
dataType: "json",
contentType: "application/json",
data: JSON.stringify(body),
});
}
</script>
</body>
</html>
5.请求接口
@RestController
public class TestController {
@Autowired
private StringRedisTemplate stringRedisTemplate;
/**
* 登录之前,调用此接口,获取密钥对中的公钥,将公钥和唯一标识给客户端
* 私钥存储在服务端,这边存储在redis中,每次获取的密钥对都不一样,一个公钥加密的,只能由对应的私钥进行解密
*
* @return
*/
@GetMapping("getPublicKey")
public HashMap<String, Object> getPublicKey() {
KeyPair keyPair = RSAUtils2.generateKeyPair();
String base64PublicKey = RSAUtils2.getBase64PublicKey(keyPair.getPublic());
String privateKey = RSAUtils2.getBase64PrivateKey(keyPair.getPrivate());
// 每次获取密钥对的时候,生成一个唯一标识,前端进行存储,在登录的时候带上这个唯一标识
String uuid = UUID.randomUUID().toString();
stringRedisTemplate.opsForValue().set("private_key:" + uuid, privateKey, 5L, TimeUnit.MINUTES);
HashMap<String, Object> map = new HashMap<>(2);
map.put("uuid", uuid);
map.put("base64PublicKey", base64PublicKey);
return map;
}
/**
* 通过唯一标识,从redis中查询对应的秘钥,通过秘钥进行解密,然后将该key从redis中remove
*/
@PostMapping("login")
public void login(@RequestBody LoginBody loginBody) {
String privateKey = stringRedisTemplate.opsForValue().get("private_key:" + loginBody.getUuid());
String username = RSAUtils2.decrypt(loginBody.getUsername(), privateKey);
String password = RSAUtils2.decrypt(loginBody.getPassword(), privateKey);
System.out.println(username);
System.out.println(password);
stringRedisTemplate.delete("private_key:" + loginBody.getUuid());
}
}
@Data
public class LoginBody {
private String username;
private String password;
private String uuid;
}
- RSA工具类
package com.angel.item.utils;
import org.apache.tomcat.util.codec.binary.Base64;
import javax.crypto.Cipher;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
public class RSAUtils2 {
public static final String RSA_ECB_PKCS1_PADDING = "RSA/ECB/PKCS1Padding";
public static final int KEY_SIZE_2048 = 2048;
public static final int KEY_SIZE_1024 = 1024;
private static final String ALGORITHM = "RSA";
public static KeyPair generateKeyPair() {
return generateKeyPair(KEY_SIZE_2048);
}
public static KeyPair generateKeyPair(int keySize) {
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
keyPairGenerator.initialize(keySize);
return keyPairGenerator.generateKeyPair();
} catch (NoSuchAlgorithmException e) {
throw new IllegalArgumentException("Failed to generate key pair!", e);
}
}
public static PublicKey getPublicKey(String base64PublicKey) {
try {
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decodeBase64(base64PublicKey));
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
PublicKey publicKey = keyFactory.generatePublic(keySpec);
return publicKey;
} catch (Exception e) {
throw new IllegalArgumentException("Failed to get public key!", e);
}
}
public static PublicKey getPublicKey(BigInteger modulus, BigInteger exponent) {
try {
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, exponent);
return keyFactory.generatePublic(keySpec);
} catch (Exception e) {
throw new IllegalArgumentException("Failed to get public key!", e);
}
}
public static String getBase64PublicKey(PublicKey publicKey) {
return Base64.encodeBase64String(publicKey.getEncoded());
}
public static PrivateKey getPrivateKey(String base64PrivateKey) {
try {
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(base64PrivateKey));
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
return privateKey;
} catch (Exception e) {
throw new IllegalArgumentException("Failed to get private key!", e);
}
}
public static PrivateKey getPrivateKey(BigInteger modulus, BigInteger exponent) {
try {
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(modulus, exponent);
return keyFactory.generatePrivate(keySpec);
} catch (Exception e) {
throw new IllegalArgumentException("Failed to get private key!", e);
}
}
public static String getBase64PrivateKey(PrivateKey privateKey) {
return Base64.encodeBase64String(privateKey.getEncoded());
}
public static byte[] encryptAsByteArray(String data, PublicKey publicKey) {
try {
Cipher cipher = Cipher.getInstance(RSA_ECB_PKCS1_PADDING);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(data.getBytes());
} catch (Exception e) {
throw new IllegalArgumentException("Encrypt failed!", e);
}
}
public static byte[] encryptAsByteArray(String data, String base64PublicKey) {
return encryptAsByteArray(data, getPublicKey(base64PublicKey));
}
public static String encryptAsString(String data, PublicKey publicKey) {
return Base64.encodeBase64String(encryptAsByteArray(data, publicKey));
}
public static String encryptAsString(String data, String base64PublicKey) {
return Base64.encodeBase64String(encryptAsByteArray(data, getPublicKey(base64PublicKey)));
}
public static String decrypt(byte[] data, PrivateKey privateKey) {
try {
Cipher cipher = Cipher.getInstance(RSA_ECB_PKCS1_PADDING);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return new String(cipher.doFinal(data));
} catch (Exception e) {
throw new IllegalArgumentException("解码失败!", e);
}
}
public static String decrypt(byte[] data, String base64PrivateKey) {
return decrypt(data, getPrivateKey(base64PrivateKey));
}
public static String decrypt(String data, PrivateKey privateKey) {
return decrypt(Base64.decodeBase64(data), privateKey);
}
public static String decrypt(String data, String base64PrivateKey) {
return decrypt(Base64.decodeBase64(data), getPrivateKey(base64PrivateKey));
}
public static void main(String[] args) {
/*生成密钥对*/
KeyPair keyPair = RSAUtils2.generateKeyPair();
String privateKey = Base64.encodeBase64String(keyPair.getPrivate().getEncoded());
String publicKey = Base64.encodeBase64String(keyPair.getPublic().getEncoded());
System.out.println("私钥privateKey:" + privateKey);
System.out.println("公钥publicKey:" + publicKey);
String content = "18811122222";
System.out.println("原始字符串:" + content);
//公钥加密
String encryptAsString = RSAUtils2.encryptAsString(content, publicKey);
System.out.println("rsa加密后字符串:" + encryptAsString);
//私钥解密
String decrypt = RSAUtils2.decrypt(encryptAsString, privateKey);
System.out.println("rsa解密后字符串:" + decrypt);
}
}