加密方法 国密SM2、 RSA(集成Redis)、 BCrypt加密
国密SM2的用法:
引入依赖
pom.xml
<!-- 国密SM2 -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.70</version>
</dependency>
SM2工具类
SM2Util
package com.zxd.SM2;
/**
* @Auther: Zxd
* @Date: 2024/07/16 14:58
* @Description: SM2加解密、签名验签工具类
*/
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.crypto.signers.SM2Signer;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Base64;
import java.math.BigInteger;
import java.security.*;
public class SM2Util {
// 初始化BouncyCastleProvider
static {
Security.addProvider(new BouncyCastleProvider());
}
// 获取SM2曲线参数
private static final X9ECParameters CURVE = GMNamedCurves.getByName("sm2p256v1");
// 定义ECDomainParameters对象
private static final ECDomainParameters DOMAIN_PARAMS = new ECDomainParameters(CURVE.getCurve(), CURVE.getG(), CURVE.getN());
/**
* 生成SM2密钥对
*
* @return AsymmetricCipherKeyPair 密钥对
*/
public static AsymmetricCipherKeyPair generateKeyPair() throws NoSuchProviderException, NoSuchAlgorithmException, InvalidAlgorithmParameterException {
ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
ECKeyGenerationParameters keyGenParam = new ECKeyGenerationParameters(DOMAIN_PARAMS, new SecureRandom());
keyPairGenerator.init(keyGenParam);
return keyPairGenerator.generateKeyPair();
}
/**
* 使用公钥加密数据
*
* @param data 待加密数据
* @param publicKey 公钥参数
* @return 加密后的字节数组
*/
public static byte[] encrypt(byte[] data, ECPublicKeyParameters publicKey) throws Exception {
SM2Engine engine = new SM2Engine();
ParametersWithRandom pwr = new ParametersWithRandom(publicKey, new SecureRandom());
engine.init(true, pwr);
return engine.processBlock(data, 0, data.length);
}
/**
* 使用私钥解密数据
*
* @param encryptedData 加密后的数据
* @param privateKey 私钥参数
* @return 解密后的字节数组
*/
public static byte[] decrypt(byte[] encryptedData, ECPrivateKeyParameters privateKey) throws Exception {
SM2Engine engine = new SM2Engine();
engine.init(false, privateKey);
return engine.processBlock(encryptedData, 0, encryptedData.length);
}
/**
* 使用私钥对数据进行签名
*
* @param data 待签名数据
* @param privateKey 私钥参数
* @return 签名后的字节数组
*/
public static byte[] sign(byte[] data, ECPrivateKeyParameters privateKey) throws Exception {
SM2Signer signer = new SM2Signer();
CipherParameters param = new ParametersWithID(privateKey, new byte[0]);
signer.init(true, param);
signer.update(data, 0, data.length);
return signer.generateSignature();
}
/**
* 使用公钥验证签名
*
* @param data 原始数据
* @param signature 签名
* @param publicKey 公钥参数
* @return 验证结果,true表示验证通过,false表示验证失败
*/
public static boolean verify(byte[] data, byte[] signature, ECPublicKeyParameters publicKey) throws Exception {
SM2Signer signer = new SM2Signer();
CipherParameters param = new ParametersWithID(publicKey, new byte[0]);
signer.init(false, param);
signer.update(data, 0, data.length);
return signer.verifySignature(signature);
}
/**
* 将Base64编码的公钥字符串转换为ECPublicKeyParameters对象
*
* @param base64PublicKey Base64编码的公钥字符串
* @return ECPublicKeyParameters对象
*/
public static ECPublicKeyParameters convertBase64StringToPublicKey(String base64PublicKey) throws Exception {
byte[] pubKeyBytes = Base64.decode(base64PublicKey);
ECPoint pubPoint = CURVE.getCurve().decodePoint(pubKeyBytes);
return new ECPublicKeyParameters(pubPoint, DOMAIN_PARAMS);
}
/**
* 将Base64编码的私钥字符串转换为ECPrivateKeyParameters对象
*
* @param base64PrivateKey Base64编码的私钥字符串
* @return ECPrivateKeyParameters对象
*/
public static ECPrivateKeyParameters convertBase64StringToPrivateKey(String base64PrivateKey) throws Exception {
byte[] privKeyBytes = Base64.decode(base64PrivateKey);
BigInteger privateKeyD = new BigInteger(1, privKeyBytes);
return new ECPrivateKeyParameters(privateKeyD, DOMAIN_PARAMS);
}
/**
* 将ECPublicKeyParameters对象转换为Base64编码的字符串
*
* @param publicKey 公钥参数
* @return Base64编码的公钥字符串
*/
public static String convertPublicKeyToBase64String(ECPublicKeyParameters publicKey) {
return Base64.toBase64String(publicKey.getQ().getEncoded(true));
}
/**
* 将ECPrivateKeyParameters对象转换为Base64编码的字符串
*
* @param privateKey 私钥参数
* @return Base64编码的私钥字符串
*/
public static String convertPrivateKeyToBase64String(ECPrivateKeyParameters privateKey) {
return Base64.toBase64String(privateKey.getD().toByteArray());
}
}
SM2控制器
EncryptionController
package com.zxd.SM2;
/**
* @Auther: Zxd
* @Date: 2024/07/16 15:06
* @Description: 加密控制器
*/
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.springframework.web.bind.annotation.*;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/encryption")
@Tag(name = "SM2模块")
public class EncryptionController {
/**
* 生成SM2密钥对
*
* @return 包含Base64编码的公钥和私钥字符串的Map
*/
@GetMapping("/generateKeys")
@Operation(summary = "生成SM2密钥对")
public Map<String, String> generateKeys() throws Exception {
AsymmetricCipherKeyPair keyPair = SM2Util.generateKeyPair();
ECPrivateKeyParameters privateKey = (ECPrivateKeyParameters) keyPair.getPrivate();
ECPublicKeyParameters publicKey = (ECPublicKeyParameters) keyPair.getPublic();
Map<String, String> keys = new HashMap<>();
keys.put("publicKey", SM2Util.convertPublicKeyToBase64String(publicKey));
keys.put("privateKey", SM2Util.convertPrivateKeyToBase64String(privateKey));
return keys;
}
/**
* 使用公钥加密数据
*
* @param data 待加密数据
* @param publicKey Base64编码的公钥字符串
* @return Base64编码的加密后字符串
*/
@PostMapping("/encrypt")
@Operation(summary = "使用公钥加密数据")
public String encrypt(@RequestParam String data, @RequestParam String publicKey) throws Exception {
ECPublicKeyParameters pubKey = SM2Util.convertBase64StringToPublicKey(publicKey);
byte[] encryptedData = SM2Util.encrypt(data.getBytes(), pubKey);
return Base64.getEncoder().encodeToString(encryptedData);
}
/**
* 使用私钥解密数据
*
* @param encryptedData Base64编码的加密后字符串
* @param privateKey Base64编码的私钥字符串
* @return 解密后的字符串
*/
@PostMapping("/decrypt")
@Operation(summary = "使用私钥解密数据")
public String decrypt(@RequestParam String encryptedData, @RequestParam String privateKey) throws Exception {
ECPrivateKeyParameters privKey = SM2Util.convertBase64StringToPrivateKey(privateKey);
byte[] decodedData = Base64.getDecoder().decode(encryptedData);
byte[] decryptedData = SM2Util.decrypt(decodedData, privKey);
return new String(decryptedData);
}
/**
* 使用私钥对数据进行签名
*
* @param data 待签名数据
* @param privateKey Base64编码的私钥字符串
* @return Base64编码的签名字符串
*/
@PostMapping("/sign")
@Operation(summary = "使用私钥对数据进行签名")
public String sign(@RequestParam String data, @RequestParam String privateKey) throws Exception {
ECPrivateKeyParameters privKey = SM2Util.convertBase64StringToPrivateKey(privateKey);
byte[] signature = SM2Util.sign(data.getBytes(), privKey);
return Base64.getEncoder().encodeToString(signature);
}
/**
* 使用公钥验证签名
*
* @param data 原始数据
* @param signature Base64编码的签名字符串
* @param publicKey Base64编码的公钥字符串
* @return 验证结果,true表示验证通过,false表示验证失败
*/
@PostMapping("/verify")
@Operation(summary = "使用公钥验证签名")
public boolean verify(@RequestParam String data, @RequestParam String signature, @RequestParam String publicKey) throws Exception {
ECPublicKeyParameters pubKey = SM2Util.convertBase64StringToPublicKey(publicKey);
byte[] decodedSignature = Base64.getDecoder().decode(signature);
return SM2Util.verify(data.getBytes(), decodedSignature, pubKey);
}
}
以上是生成秘钥和两对方法的基本使用实例
Rsa的用法:
后端生成秘钥对,把私钥存redis,并且把key和公钥返回给前端
前端加密之后吧密文和key传过来,后端通过key获取私钥解密
国密SM2和Rsa都属于加密传输数据 Rsa是国际广泛使用,SM2更适合中国且效率和安全性优于Rsa(Rsa字符串过长且可以被量子计算机破解)
配置RSAUtil
RSAUtil
package com.zxd.RSA;
/**
* @Auther: Zxd
* @Date: 2024/07/16 10:52
* @Description:
*/
import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class RSAUtil {
//签名算法名称
private static final String RSA_KEY_ALGORITHM = "RSA";
//标准签名算法名称
private static final String RSA_SIGNATURE_ALGORITHM = "SHA1withRSA";
private static final String RSA2_SIGNATURE_ALGORITHM = "SHA256withRSA";
//RSA密钥长度,默认密钥长度是1024,密钥长度必须是64的倍数,在512到65536位之间,不管是RSA还是RSA2长度推荐使用2048
private static final int KEY_SIZE = 2048;
/**
* 生成密钥对
*
* @return 返回包含公私钥的map
*/
public static Map<String, String> generateKey() {
KeyPairGenerator keygen;
try {
keygen = KeyPairGenerator.getInstance(RSA_KEY_ALGORITHM);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("RSA初始化密钥出现错误,算法异常");
}
SecureRandom secrand = new SecureRandom();
//初始化随机产生器
secrand.setSeed("Alian".getBytes());
//初始化密钥生成器
keygen.initialize(KEY_SIZE, secrand);
KeyPair keyPair = keygen.genKeyPair();
//获取公钥并转成base64编码
byte[] pub_key = keyPair.getPublic().getEncoded();
String publicKeyStr = Base64.getEncoder().encodeToString(pub_key);
//获取私钥并转成base64编码
byte[] pri_key = keyPair.getPrivate().getEncoded();
String privateKeyStr = Base64.getEncoder().encodeToString(pri_key);
//创建一个Map返回结果
Map<String, String> keyPairMap = new HashMap<>();
keyPairMap.put("publicKeyStr", publicKeyStr);
keyPairMap.put("privateKeyStr", privateKeyStr);
return keyPairMap;
}
/**
* 公钥加密(用于数据加密)
*
* @param data 加密前的字符串
* @param publicKeyStr base64编码后的公钥
* @return base64编码后的字符串
* @throws Exception
*/
public static String encryptByPublicKey(String data, String publicKeyStr) throws Exception {
//Java原生base64解码
byte[] pubKey = Base64.getDecoder().decode(publicKeyStr);
//创建X509编码密钥规范
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKey);
//返回转换指定算法的KeyFactory对象
KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
//根据X509编码密钥规范产生公钥对象
PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
//根据转换的名称获取密码对象Cipher(转换的名称:算法/工作模式/填充模式)
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
//用公钥初始化此Cipher对象(加密模式)
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
//对数据加密
byte[] encrypt = cipher.doFinal(data.getBytes());
//返回base64编码后的字符串
return Base64.getEncoder().encodeToString(encrypt);
}
/**
* 私钥解密(用于数据解密)
*
* @param data 解密前的字符串
* @param privateKeyStr 私钥
* @return 解密后的字符串
* @throws Exception
*/
public static String decryptByPrivateKey(String data, String privateKeyStr) throws Exception {
//Java原生base64解码
byte[] priKey = Base64.getDecoder().decode(privateKeyStr);
//创建PKCS8编码密钥规范
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(priKey);
//返回转换指定算法的KeyFactory对象
KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
//根据PKCS8编码密钥规范产生私钥对象
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
//根据转换的名称获取密码对象Cipher(转换的名称:算法/工作模式/填充模式)
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
//用私钥初始化此Cipher对象(解密模式)
cipher.init(Cipher.DECRYPT_MODE, privateKey);
//对数据解密
byte[] decrypt = cipher.doFinal(Base64.getDecoder().decode(data));
//返回字符串
return new String(decrypt);
}
/**
* 私钥加密(用于数据签名)
*
* @param data 加密前的字符串
* @param privateKeyStr base64编码后的私钥
* @return base64编码后后的字符串
* @throws Exception
*/
public static String encryptByPrivateKey(String data, String privateKeyStr) throws Exception {
//Java原生base64解码
byte[] priKey = Base64.getDecoder().decode(privateKeyStr);
//创建PKCS8编码密钥规范
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(priKey);
//返回转换指定算法的KeyFactory对象
KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
//根据PKCS8编码密钥规范产生私钥对象
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
//根据转换的名称获取密码对象Cipher(转换的名称:算法/工作模式/填充模式)
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
//用私钥初始化此Cipher对象(加密模式)
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
//对数据加密
byte[] encrypt = cipher.doFinal(data.getBytes());
//返回base64编码后的字符串
return Base64.getEncoder().encodeToString(encrypt);
}
/**
* 公钥解密(用于数据验签)
*
* @param data 解密前的字符串
* @param publicKeyStr base64编码后的公钥
* @return 解密后的字符串
* @throws Exception
*/
public static String decryptByPublicKey(String data, String publicKeyStr) throws Exception {
//Java原生base64解码
byte[] pubKey = Base64.getDecoder().decode(publicKeyStr);
//创建X509编码密钥规范
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKey);
//返回转换指定算法的KeyFactory对象
KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
//根据X509编码密钥规范产生公钥对象
PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
//根据转换的名称获取密码对象Cipher(转换的名称:算法/工作模式/填充模式)
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
//用公钥初始化此Cipher对象(解密模式)
cipher.init(Cipher.DECRYPT_MODE, publicKey);
//对数据解密
byte[] decrypt = cipher.doFinal(Base64.getDecoder().decode(data));
//返回字符串
return new String(decrypt);
}
/**
* RSA签名
*
* @param data 待签名数据
* @param priKey 私钥
* @param signType RSA或RSA2 默认为RSA2
* @return 签名
* @throws Exception
*/
public static String sign(byte[] data, byte[] priKey, String signType) throws Exception {
//创建PKCS8编码密钥规范
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(priKey);
//返回转换指定算法的KeyFactory对象
KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
//根据PKCS8编码密钥规范产生私钥对象
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
//标准签名算法名称(RSA还是RSA2)
String algorithm = RSA_KEY_ALGORITHM.equals(signType) ? RSA_SIGNATURE_ALGORITHM : RSA2_SIGNATURE_ALGORITHM;
//用指定算法产生签名对象Signature
Signature signature = Signature.getInstance(algorithm);
//用私钥初始化签名对象Signature
signature.initSign(privateKey);
//将待签名的数据传送给签名对象(须在初始化之后)
signature.update(data);
//返回签名结果字节数组
byte[] sign = signature.sign();
//返回Base64编码后的字符串
return Base64.getEncoder().encodeToString(sign);
}
/**
* RSA校验数字签名
*
* @param data 待校验数据
* @param sign 数字签名
* @param pubKey 公钥
* @param signType RSA或RSA2 默认为RSA2
* @return boolean 校验成功返回true,失败返回false
*/
public static boolean verify(byte[] data, byte[] sign, byte[] pubKey, String signType) throws Exception {
//返回转换指定算法的KeyFactory对象
KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
//创建X509编码密钥规范
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKey);
//根据X509编码密钥规范产生公钥对象
PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
//标准签名算法名称(RSA还是RSA2)
String algorithm = RSA_KEY_ALGORITHM.equals(signType) ? RSA_SIGNATURE_ALGORITHM : RSA2_SIGNATURE_ALGORITHM;
//用指定算法产生签名对象Signature
Signature signature = Signature.getInstance(algorithm);
//用公钥初始化签名对象,用于验证签名
signature.initVerify(publicKey);
//更新签名内容
signature.update(data);
//得到验证结果
return signature.verify(sign);
}
}
Rsa控制器
RSAUtilController
package com.zxd.RSA;
/**
* @Auther: Zxd
* @Date: 2024/07/18 14:02
* @Description:
*/
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import java.util.Base64;
import java.util.Map;
@RestController
@RequestMapping("/rsa")
@Tag(name = "RSA模块")
public class RSAUtilController {
/**
* 生成RSA密钥对
*
* @return 包含Base64编码的公钥和私钥字符串的Map
*/
@GetMapping("/generateKeys")
@Operation(summary = "生成RSA密钥对")
public Map<String, String> generateKeys() {
return RsaUtil.generateKey();
}
/**
* 使用公钥加密数据
*
* @param data 待加密数据
* @param publicKey Base64编码的公钥字符串
* @return Base64编码的加密后字符串
*/
@PostMapping("/encryptByPublicKey")
@Operation(summary = "使用公钥加密数据")
public String encryptByPublicKey(@RequestParam String data, @RequestParam String publicKey) throws Exception {
return RsaUtil.encryptByPublicKey(data, publicKey);
}
/**
* 使用私钥解密数据
*
* @param encryptedData Base64编码的加密后字符串
* @param privateKey Base64编码的私钥字符串
* @return 解密后的字符串
*/
@PostMapping("/decryptByPrivateKey")
@Operation(summary = "使用私钥解密数据")
public String decryptByPrivateKey(@RequestParam String encryptedData, @RequestParam String privateKey) throws Exception {
return RsaUtil.decryptByPrivateKey(encryptedData, privateKey);
}
/**
* 使用私钥加密数据
*
* @param data 待加密数据
* @param privateKey Base64编码的私钥字符串
* @return Base64编码的加密后字符串
*/
@PostMapping("/encryptByPrivateKey")
@Operation(summary = "使用私钥加密数据")
public String encryptByPrivateKey(@RequestParam String data, @RequestParam String privateKey) throws Exception {
return RsaUtil.encryptByPrivateKey(data, privateKey);
}
/**
* 使用公钥解密数据
*
* @param encryptedData Base64编码的加密后字符串
* @param publicKey Base64编码的公钥字符串
* @return 解密后的字符串
*/
@PostMapping("/decryptByPublicKey")
@Operation(summary = "使用公钥解密数据")
public String decryptByPublicKey(@RequestParam String encryptedData, @RequestParam String publicKey) throws Exception {
return RsaUtil.decryptByPublicKey(encryptedData, publicKey);
}
/**
* RSA签名
*
* @param data 待签名数据
* @param privateKey Base64编码的私钥字符串
* @param signType 签名类型(RSA或RSA2) 默认为RSA2
* @return Base64编码的签名字符串
*/
@PostMapping("/sign")
@Operation(summary = "RSA签名")
public String sign(@RequestParam String data, @RequestParam String privateKey, @RequestParam String signType) throws Exception {
byte[] priKey = Base64.getDecoder().decode(privateKey);
return RsaUtil.sign(data.getBytes(), priKey, signType);
}
/**
* RSA校验数字签名
*
* @param data 原始数据
* @param signature Base64编码的签名字符串
* @param publicKey Base64编码的公钥字符串
* @param signType 签名类型(RSA或RSA2) 默认为RSA2
* @return 校验结果,true表示校验通过,false表示校验失败
*/
@PostMapping("/verify")
@Operation(summary = "RSA校验数字签名")
public boolean verify(@RequestParam String data, @RequestParam String signature, @RequestParam String publicKey, @RequestParam String signType) throws Exception {
byte[] pubKey = Base64.getDecoder().decode(publicKey);
byte[] sig = Base64.getDecoder().decode(signature);
return RsaUtil.verify(data.getBytes(), sig, pubKey, signType);
}
}
包含了生成秘钥和三对基本的使用方法
Redis的配置:
1. 引入依赖,配置pom.xml文件
pom.xml
<!--Redis 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2. yml文件:
application.yml
spring:
data:
redis:
# Redis数据库索引(默认为0)
database: 5
host: 39.170.99.28
port: 6379
password: aofakeji2024
3. 配置RedisConfig
RedisConfig
package com.zxd.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* @Auther: Zxd
* @Date: 2024/07/16 10:47
* @Description:
*/
@Configuration
public class RedisConfig {
/**
* 配置RedisTemplate,用于操作Redis数据库。
* 通过此方法,我们可以定制RedisTemplate的行为,例如设置序列化器。
*
* @param redisConnectionFactory Redis连接工厂,用于创建Redis连接。
* @return RedisTemplate实例,配置了字符串和对象的序列化方式。
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 设置ConnectionFactory,用于实际与Redis服务器的通信。
template.setConnectionFactory(redisConnectionFactory);
// 设置键的序列化方式为StringRedisSerializer,保证键的序列化一致性。
template.setKeySerializer(new StringRedisSerializer());
// 设置值的序列化方式为GenericJackson2JsonRedisSerializer,使用Jackson库将对象序列化为JSON格式。
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
return template;
}
}
4. 配置RedisUtil
RedisUtil
package com.zxd.utils;
/**
* @Auther: Zxd
* @Date: 2024/07/16 11:27
* @Description:
*/
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* spring redis 工具类
*
* @author wr
**/
@SuppressWarnings(value = { "unchecked", "rawtypes" })
@Component
public class RedisUtil
{
@Autowired
public RedisTemplate redisTemplate;
/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
*/
public <T> void setCacheObject(final String key, final T value)
{
redisTemplate.opsForValue().set(key, value);
}
/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
* @param timeout 时间
* @param timeUnit 时间颗粒度
*/
public <T> void setCacheObject(final String key, final T value, final Long timeout, final TimeUnit timeUnit)
{
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
}
/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @return true=设置成功;false=设置失败
*/
public boolean expire(final String key, final long timeout)
{
return expire(key, timeout, TimeUnit.SECONDS);
}
/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @param unit 时间单位
* @return true=设置成功;false=设置失败
*/
public boolean expire(final String key, final long timeout, final TimeUnit unit)
{
return redisTemplate.expire(key, timeout, unit);
}
/**
* 获取有效时间
*
* @param key Redis键
* @return 有效时间
*/
public long getExpire(final String key)
{
return redisTemplate.getExpire(key);
}
/**
* 判断 key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public Boolean hasKey(String key)
{
return redisTemplate.hasKey(key);
}
/**
* 获得缓存的基本对象。
*
* @param key 缓存键值
* @return 缓存键值对应的数据
*/
public <T> T getCacheObject(final String key)
{
ValueOperations<String, T> operation = redisTemplate.opsForValue();
return operation.get(key);
}
/**
* 删除单个对象
*
* @param key
*/
public boolean deleteObject(final String key)
{
return redisTemplate.delete(key);
}
/**
* 删除集合对象
*
* @param collection 多个对象
* @return
*/
public boolean deleteObject(final Collection collection)
{
return redisTemplate.delete(collection) > 0;
}
/**
* 缓存List数据
*
* @param key 缓存的键值
* @param dataList 待缓存的List数据
* @return 缓存的对象
*/
public <T> long setCacheList(final String key, final List<T> dataList)
{
Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
return count == null ? 0 : count;
}
/**
* 获得缓存的list对象
*
* @param key 缓存的键值
* @return 缓存键值对应的数据
*/
public <T> List<T> getCacheList(final String key)
{
return redisTemplate.opsForList().range(key, 0, -1);
}
/**
* 缓存Set
*
* @param key 缓存键值
* @param dataSet 缓存的数据
* @return 缓存数据的对象
*/
public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet)
{
BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
Iterator<T> it = dataSet.iterator();
while (it.hasNext())
{
setOperation.add(it.next());
}
return setOperation;
}
/**
* 获得缓存的set
*
* @param key
* @return
*/
public <T> Set<T> getCacheSet(final String key)
{
return redisTemplate.opsForSet().members(key);
}
/**
* 缓存Map
*
* @param key
* @param dataMap
*/
public <T> void setCacheMap(final String key, final Map<String, T> dataMap)
{
if (dataMap != null) {
redisTemplate.opsForHash().putAll(key, dataMap);
}
}
/**
* 获得缓存的Map
*
* @param key
* @return
*/
public <T> Map<String, T> getCacheMap(final String key)
{
return redisTemplate.opsForHash().entries(key);
}
/**
* 往Hash中存入数据
*
* @param key Redis键
* @param hKey Hash键
* @param value 值
*/
public <T> void setCacheMapValue(final String key, final String hKey, final T value)
{
redisTemplate.opsForHash().put(key, hKey, value);
}
/**
* 获取Hash中的数据
*
* @param key Redis键
* @param hKey Hash键
* @return Hash中的对象
*/
public <T> T getCacheMapValue(final String key, final String hKey)
{
HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
return opsForHash.get(key, hKey);
}
/**
* 获取多个Hash中的数据
*
* @param key Redis键
* @param hKeys Hash键集合
* @return Hash对象集合
*/
public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys)
{
return redisTemplate.opsForHash().multiGet(key, hKeys);
}
/**
* 删除Hash中的某条数据
*
* @param key Redis键
* @param hKey Hash键
* @return 是否成功
*/
public boolean deleteCacheMapValue(final String key, final String hKey)
{
return redisTemplate.opsForHash().delete(key, hKey) > 0;
}
/**
* 获得缓存的基本对象列表
*
* @param pattern 字符串前缀
* @return 对象列表
*/
public Collection<String> keys(final String pattern)
{
return redisTemplate.keys(pattern);
}
}
Rsa测试类
RsaTest
package com.zxd;
import com.zxd.utils.RedisUtil;
import com.zxd.utils.RsaUtil;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Base64;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* @Auther: Zxd
* @Date: 2024/07/16 10:02
* @Description:
*/
@SpringBootTest
public class RsaTest {
/**
* RSA数据加密和解密
*
* @throws Exception
*/
@Autowired
private RedisUtil redisUtil;
// 加密
@Test
public void encryptAndDecrypt() throws Exception {
// 生成密钥对
Map<String, String> keyMap = RsaUtil.generateKey();
String publicKeyStr = keyMap.get("publicKeyStr");
String privateKeyStr = keyMap.get("privateKeyStr");
System.out.println("-----------------生成的公钥和私钥------------------------------");
System.out.println("获取到的公钥:" + publicKeyStr);
System.out.println("获取到的私钥:" + privateKeyStr);
// 待加密数据
String data = "tranSeq=1920542585&amount=100&payType=wechat";
String username = "zxd";
System.out.println("-----------------加密和解密------------------------------");
System.out.println("待加密的数据:" + data);
// 将私钥存储到Redis
redisUtil.setCacheObject(username, privateKeyStr,5L, TimeUnit.MINUTES);
// 公钥加密
String encrypt = RsaUtil.encryptByPublicKey(data, publicKeyStr);
System.out.println("加密后数据:" + encrypt);
String jiemi = jiemi(username,encrypt);
System.out.println("解密后数据:" + jiemi);
// 从Redis中获取私钥进行解密
// String privateKeyFromRedis = redisUtil.getCacheObject("privateKeyStr");
// String decrypt = RsaUtil.decryptByPrivateKey(encrypt, privateKeyFromRedis);
// System.out.println("解密后数据:" + decrypt);
}
// 解密
@Test
public String jiemi(String username,String encrypt) throws Exception {
// 从Redis中获取私钥进行解密
String privateKeyFromRedis = redisUtil.getCacheObject(username);
String decrypt = RsaUtil.decryptByPrivateKey(encrypt, privateKeyFromRedis);
// System.out.println("解密后数据:" + decrypt);
return decrypt;
}
/**
* RSA数据签名和验签
*
* @throws Exception
*/
@Test
public void signAndVerify() throws Exception {
Map<String, String> keyMap = RsaUtil.generateKey();
String publicKeyStr = keyMap.get("publicKeyStr");
String privateKeyStr = keyMap.get("privateKeyStr");
System.out.println("-----------------生成的公钥和私钥------------------------------");
System.out.println("获取到的公钥:" + publicKeyStr);
System.out.println("获取到的私钥:" + privateKeyStr);
// 数字签名
String data = "tranSeq=1920542585&amount=100&payType=wechat";
String username = "zxd";
System.out.println("待签名的数据:" + data);
String sign = RsaUtil.sign(data.getBytes(), Base64.getDecoder().decode(privateKeyStr), "RSA");
// 将公钥存储到Redis
redisUtil.setCacheObject(username, publicKeyStr,5L, TimeUnit.MINUTES);
System.out.println("数字签名结果:" + sign);
boolean verify = RsaUtil.verify(data.getBytes(), Base64.getDecoder().decode(sign), Base64.getDecoder().decode(publicKeyStr), "RSA");
System.out.println("数字签名验证结果:" + verify);
}
}
BCrypt加密 (通过Sa-token集成,也可通过其他方式)
1. 引入Sa-token依赖
<!--sa-token依赖-->
<!-- Sa-Token 权限认证,在线文档:https://sa-token.cc -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot3-starter</artifactId>
<version>1.37.0</version>
</dependency>
BCryptTest
package com.zxd;
import cn.dev33.satoken.secure.BCrypt;
import org.junit.jupiter.api.Test;
/**
* @Auther: Zxd
* @Date: 2024/07/29 16:02
* @Description:
*/
public class BCryptTest {
@Test
public void bcrypt() {
// 定义明文密码
String password = "123456";
// 使用BCrypt算法加密密码
String hashpw = BCrypt.hashpw(password, BCrypt.gensalt());
// 输出加密后的密码
System.out.println("加密后的密码:" + hashpw);
// 验证明文密码和加密后的密码是否匹配
boolean checkpw = BCrypt.checkpw(password, hashpw);
// 输出验证结果
System.out.println("密码验证结果:" + checkpw);
// 生成一个强度为10的盐
String strong_salt = BCrypt.gensalt(10);
System.out.println("强度为10的盐值:" + strong_salt);
// 使用强度为10的盐值加密密码
String strong_hashpw = BCrypt.hashpw(password, strong_salt);
System.out.println("使用强度为10的盐值加密后的密码:" + strong_hashpw);
// 验证使用强度为10的盐值加密后的密码
boolean strong_checkpw = BCrypt.checkpw(password, strong_hashpw);
System.out.println("使用强度为10的盐值密码验证结果:" + strong_checkpw);
// 生成一个强度为12的盐
String stronger_salt = BCrypt.gensalt(12);
System.out.println("强度为12的盐值:" + stronger_salt);
// 使用强度为12的盐值加密密码
String stronger_hashpw = BCrypt.hashpw(password, stronger_salt);
System.out.println("使用强度为12的盐值加密后的密码:" + stronger_hashpw);
// 验证使用强度为12的盐值加密后的密码
boolean stronger_checkpw = BCrypt.checkpw(password, stronger_hashpw);
System.out.println("使用强度为12的盐值密码验证结果:" + stronger_checkpw);
// 盐的强度越高,加密的复杂度也越高,从而提供更好的安全性
}
}