【java】前端RSA加密后端解密
目录
- 1. 说明
- 2. 前端示例
- 3. 后端示例
- 3.1 pom依赖
- 3.2 后端结构图
- 3.3 DecryptHttpInputMessage
- 3.4 ApiCryptoProperties
- 3.5 TestController
- 3.6 ApiCryptoUtil
- 3.7 ApiDecryptParamResolver
- 3.8 ApiDecryptRequestBodyAdvice
- 3.9 ApiDecryptRsa
- 3.10 ApiCryptoProperties
- 3.11 KeyPair
- 3.12 Pair
- 3.13 ClassUtil
- 3.14 Func
- 3.15 RsaUtil
- 3.16 SpringBootLearningApplication启动类
- 3.17 配置文件
- 4. 调用截图
1. 说明
- 1.RSA是非对称加密。
- 2.前端采用公钥加密,后端采用私钥解密。
- 3.此示例是前端加密,后端解密,后端返回的数据未加密。如果后端相应数据也要加密,可以另写注解,采用对称加密。
- 4.公钥私钥的base64格式可以由RsaUtil工具类生成,参考其中main方法。
- 5.在需要加密的接口上添加自定义注解@ApiDecryptRsa即可解密。
- 5.ApiDecryptParamResolver是解析requestParam参数的,这里没写全,需要额外写注解。
2. 前端示例
- 1.rsa依赖包
npm install jsencrypt
- 2.页面代码
<template><el-button type="primary" icon="el-icon-plus" @click="handleTest">测试</el-button>
</template><script>
import { save } from "@/api/test";
import JSEncrypt from 'jsencrypt/bin/jsencrypt.min';
export default {name: '测试RSA加密',methods: {handleTest(){const crypt = new JSEncrypt()// 公钥,由后端接口返回,这里写死作为测试const publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJlmkqsmA28rt/bsBJ2hDEdvbIlEvnJ2fg0gm1++rXxXNEBvGyCnwnDxvztjsHtbootAdeB1D73DVfCKzCj5Le/Wv21llvriG1bAeM3zSEywPKQzW/5zhC3BODdx8vuFe3r1KxunqdXHm/67tnC/VMS85XGtCBkcfAXCJZyNE5rQIDAQAB';crypt.setPublicKey(publicKey)const data = {"content": "测试",}const encrypted = crypt.encrypt(JSON.stringify(data))console.log(encrypted)// 调用接口save(encrypted).then(res=>{console.log(res.data)})},}
}
</script>
- 3.api请求
import request from "@/axios";export const save = row => {return request({url: '/xapi/test/save',headers: {'Content-Type': 'text/plain'},method: 'post',data: row,});
};
3. 后端示例
3.1 pom依赖
- 1.pom依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>my-springboot</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.6</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>2.0.40</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.13.0</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></dependency></dependencies>
</project>
3.2 后端结构图
- 2.后端结构图

3.3 DecryptHttpInputMessage
- 3.DecryptHttpInputMessage
package com.learning.bean;import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;import java.io.InputStream;/*** <p>解密信息输入流</p>**/
@Getter
@RequiredArgsConstructor
public class DecryptHttpInputMessage implements HttpInputMessage {private final InputStream body;private final HttpHeaders headers;
}
3.4 ApiCryptoProperties
- 4.ApiCryptoProperties
package com.learning.config;import com.learning.crypto.advice.ApiDecryptParamResolver;
import com.learning.crypto.props.ApiCryptoProperties;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import java.util.List;/*** api 签名自动配置**/
@AutoConfiguration
@RequiredArgsConstructor
@EnableConfigurationProperties(ApiCryptoProperties.class)
@ConditionalOnProperty(value = ApiCryptoProperties.PREFIX + ".enabled", havingValue = "true", matchIfMissing = true)
public class ApiCryptoConfiguration implements WebMvcConfigurer {private final ApiCryptoProperties apiCryptoProperties;@Overridepublic void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {argumentResolvers.add(new ApiDecryptParamResolver(apiCryptoProperties));}}
3.5 TestController
- 5.TestController
package com.learning.controller;import com.learning.crypto.annotation.ApiDecryptRsa;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/test")
public class TestController {@PostMapping(value = "/save", produces = "text/plain")@ApiDecryptRsapublic String save(@RequestBody String data){return data;}
}
3.6 ApiCryptoUtil
- 6.ApiCryptoUtil
package com.learning.crypto.advice;import com.learning.crypto.props.ApiCryptoProperties;import java.util.Objects;
import com.learning.util.RsaUtil;
/*** <p>辅助工具类</p>**/
public class ApiCryptoUtil {/*** 选择加密方式并进行解密** @param bodyData byte array* @return 解密结果*/public static byte[] decryptData(ApiCryptoProperties properties, byte[] bodyData) {String privateKey = Objects.requireNonNull(properties.getRsaPrivateKey());return RsaUtil.decryptFromBase64(privateKey, bodyData);}}
3.7 ApiDecryptParamResolver
- 7.ApiDecryptParamResolver
package com.learning.crypto.advice;import com.fasterxml.jackson.databind.ObjectMapper;
import com.learning.crypto.annotation.ApiDecryptRsa;
import com.learning.crypto.props.ApiCryptoProperties;
import com.learning.util.Func;
import lombok.RequiredArgsConstructor;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;import java.lang.reflect.Parameter;
import java.nio.charset.StandardCharsets;/*** param 参数 解析**/
@RequiredArgsConstructor
public class ApiDecryptParamResolver implements HandlerMethodArgumentResolver {private final ApiCryptoProperties properties;@Overridepublic boolean supportsParameter(MethodParameter parameter) {return AnnotatedElementUtils.hasAnnotation(parameter.getParameter(), ApiDecryptRsa.class);}@Nullable@Overridepublic Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer mavContainer,NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {Parameter parameter = methodParameter.getParameter();String text = webRequest.getParameter(properties.getParamName());if (Func.isEmpty(text)) {return null;}byte[] textBytes = text.getBytes(StandardCharsets.UTF_8);byte[] decryptData = ApiCryptoUtil.decryptData(properties, textBytes);ObjectMapper mapper = new ObjectMapper();try{return mapper.readValue(decryptData, parameter.getType());}catch (Exception e){e.printStackTrace();return null;}}
}
3.8 ApiDecryptRequestBodyAdvice
- 8.ApiDecryptRequestBodyAdvice
package com.learning.crypto.advice;import com.learning.crypto.annotation.ApiDecryptRsa;
import com.learning.crypto.props.ApiCryptoProperties;
import com.learning.util.ClassUtil;
import com.learning.bean.DecryptHttpInputMessage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.lang.NonNull;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;/*** 请求数据的加密信息解密处理<br>* 本类只对控制器参数中含有<strong>{@link org.springframework.web.bind.annotation.RequestBody}</strong>* 以及package为<strong><code>ccom.xiaoi.xics.core.crypto.api.signature.annotation.decrypt</code></strong>下的注解有效*/
@Slf4j
@Order(1)
@AutoConfiguration
@ControllerAdvice
@RequiredArgsConstructor
@ConditionalOnProperty(value = ApiCryptoProperties.PREFIX + ".enabled", havingValue = "true", matchIfMissing = true)
public class ApiDecryptRequestBodyAdvice implements RequestBodyAdvice {private final ApiCryptoProperties properties;@Overridepublic boolean supports(MethodParameter methodParameter, @NonNull Type targetType, @NonNull Class<? extends HttpMessageConverter<?>> converterType) {return ClassUtil.isAnnotated(methodParameter.getMethod(), ApiDecryptRsa.class);}@Overridepublic Object handleEmptyBody(Object body, @NonNull HttpInputMessage inputMessage, @NonNull MethodParameter parameter, @NonNull Type targetType, @NonNull Class<? extends HttpMessageConverter<?>> converterType) {return body;}@NonNull@Overridepublic HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, @NonNull MethodParameter parameter, @NonNull Type targetType, @NonNull Class<? extends HttpMessageConverter<?>> converterType) throws IOException {// 判断 body 是否为空InputStream messageBody = inputMessage.getBody();if (messageBody.available() <= 0) {return inputMessage;}byte[] decryptedBody = null;byte[] bodyByteArray = StreamUtils.copyToByteArray(messageBody);decryptedBody = ApiCryptoUtil.decryptData(properties, bodyByteArray);if (decryptedBody == null) {throw new RuntimeException("Decryption error, " +"please check if the selected source data is encrypted correctly." +" (解密错误,请检查选择的源数据的加密方式是否正确。)");}InputStream inputStream = new ByteArrayInputStream(decryptedBody);return new DecryptHttpInputMessage(inputStream, inputMessage.getHeaders());}@NonNull@Overridepublic Object afterBodyRead(@NonNull Object body, @NonNull HttpInputMessage inputMessage, @NonNull MethodParameter parameter, @NonNull Type targetType, @NonNull Class<? extends HttpMessageConverter<?>> converterType) {return body;}}
3.9 ApiDecryptRsa
- 9.ApiDecryptRsa
package com.learning.crypto.annotation;import java.lang.annotation.*;/*** rsa 解密*/
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface ApiDecryptRsa {
}
3.10 ApiCryptoProperties
- 10.ApiCryptoProperties
package com.learning.crypto.props;import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;/*** api 签名配置类*/
@Getter
@Setter
@ConfigurationProperties(ApiCryptoProperties.PREFIX)
public class ApiCryptoProperties {/*** 前缀*/public static final String PREFIX = "api.crypto";/*** 是否开启 api 签名*/private Boolean enabled = Boolean.TRUE;/*** url的参数签名,传递的参数名。例如:/user?data=签名后的数据*/private String paramName = "data";/*** rsa 私钥*/private String rsaPrivateKey;}
3.11 KeyPair
- 11.KeyPair
package com.learning.crypto.tuple;import com.learning.util.RsaUtil;
import lombok.RequiredArgsConstructor;import java.security.PrivateKey;
import java.security.PublicKey;/*** rsa 的 key pair 封装**/
@RequiredArgsConstructor
public class KeyPair {private final java.security.KeyPair keyPair;public PublicKey getPublic() {return keyPair.getPublic();}public PrivateKey getPrivate() {return keyPair.getPrivate();}public byte[] getPublicBytes() {return this.getPublic().getEncoded();}public byte[] getPrivateBytes() {return this.getPrivate().getEncoded();}public String getPublicBase64() {return RsaUtil.getKeyString(this.getPublic());}public String getPrivateBase64() {return RsaUtil.getKeyString(this.getPrivate());}@Overridepublic String toString() {return "PublicKey=" + this.getPublicBase64() + '\n' + "PrivateKey=" + this.getPrivateBase64();}
}
3.12 Pair
- 12.Pair
package com.learning.crypto.tuple;import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;/*** tuple Pair**/
@Getter
@ToString
@EqualsAndHashCode
public class Pair<L, R> {private static final Pair<Object, Object> EMPTY = new Pair<>(null, null);private final L left;private final R right;/*** Returns an empty pair.*/@SuppressWarnings("unchecked")public static <L, R> Pair<L, R> empty() {return (Pair<L, R>) EMPTY;}/*** Constructs a pair with its left value being {@code left}, or returns an empty pair if* {@code left} is null.** @return the constructed pair or an empty pair if {@code left} is null.*/public static <L, R> Pair<L, R> createLeft(L left) {if (left == null) {return empty();} else {return new Pair<>(left, null);}}/*** Constructs a pair with its right value being {@code right}, or returns an empty pair if* {@code right} is null.** @return the constructed pair or an empty pair if {@code right} is null.*/public static <L, R> Pair<L, R> createRight(R right) {if (right == null) {return empty();} else {return new Pair<>(null, right);}}public static <L, R> Pair<L, R> create(L left, R right) {if (right == null && left == null) {return empty();} else {return new Pair<>(left, right);}}private Pair(L left, R right) {this.left = left;this.right = right;}}
3.13 ClassUtil
- 13.ClassUtil
package com.learning.util;import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.web.method.HandlerMethod;import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;/*** 类操作工具*/
public class ClassUtil extends org.springframework.util.ClassUtils {private static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer();/*** 获取方法参数信息** @param constructor 构造器* @param parameterIndex 参数序号* @return {MethodParameter}*/public static MethodParameter getMethodParameter(Constructor<?> constructor, int parameterIndex) {MethodParameter methodParameter = new SynthesizingMethodParameter(constructor, parameterIndex);methodParameter.initParameterNameDiscovery(PARAMETER_NAME_DISCOVERER);return methodParameter;}/*** 获取方法参数信息** @param method 方法* @param parameterIndex 参数序号* @return {MethodParameter}*/public static MethodParameter getMethodParameter(Method method, int parameterIndex) {MethodParameter methodParameter = new SynthesizingMethodParameter(method, parameterIndex);methodParameter.initParameterNameDiscovery(PARAMETER_NAME_DISCOVERER);return methodParameter;}/*** 获取Annotation** @param method Method* @param annotationType 注解类* @param <A> 泛型标记* @return {Annotation}*/public static <A extends Annotation> A getAnnotation(Method method, Class<A> annotationType) {Class<?> targetClass = method.getDeclaringClass();// The method may be on an interface, but we need attributes from the target class.// If the target class is null, the method will be unchanged.Method specificMethod = ClassUtil.getMostSpecificMethod(method, targetClass);// If we are dealing with method with generic parameters, find the original method.specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);// 先找方法,再找方法上的类A annotation = AnnotatedElementUtils.findMergedAnnotation(specificMethod, annotationType);;if (null != annotation) {return annotation;}// 获取类上面的Annotation,可能包含组合注解,故采用spring的工具类return AnnotatedElementUtils.findMergedAnnotation(specificMethod.getDeclaringClass(), annotationType);}/*** 获取Annotation** @param handlerMethod HandlerMethod* @param annotationType 注解类* @param <A> 泛型标记* @return {Annotation}*/public static <A extends Annotation> A getAnnotation(HandlerMethod handlerMethod, Class<A> annotationType) {// 先找方法,再找方法上的类A annotation = handlerMethod.getMethodAnnotation(annotationType);if (null != annotation) {return annotation;}// 获取类上面的Annotation,可能包含组合注解,故采用spring的工具类Class<?> beanType = handlerMethod.getBeanType();return AnnotatedElementUtils.findMergedAnnotation(beanType, annotationType);}/*** 判断是否有注解 Annotation** @param method Method* @param annotationType 注解类* @param <A> 泛型标记* @return {boolean}*/public static <A extends Annotation> boolean isAnnotated(Method method, Class<A> annotationType) {// 先找方法,再找方法上的类boolean isMethodAnnotated = AnnotatedElementUtils.isAnnotated(method, annotationType);if (isMethodAnnotated) {return true;}// 获取类上面的Annotation,可能包含组合注解,故采用spring的工具类Class<?> targetClass = method.getDeclaringClass();return AnnotatedElementUtils.isAnnotated(targetClass, annotationType);}}
3.14 Func
- 14.Func
package com.learning.util;import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;/*** 工具类*/
public class Func {/*** 判断空对象 object、map、list、set、字符串、数组** @param obj the object to check* @return 数组是否为空*/public static boolean isEmpty(@Nullable Object obj) {return ObjectUtils.isEmpty(obj);}/*** 对象不为空 object、map、list、set、字符串、数组** @param obj the object to check* @return 是否不为空*/public static boolean isNotEmpty(@Nullable Object obj) {return !ObjectUtils.isEmpty(obj);}}
3.15 RsaUtil
- 15.RsaUtil
package com.learning.util;import com.learning.crypto.tuple.KeyPair;
import org.springframework.lang.Nullable;
import org.springframework.util.Base64Utils;import javax.crypto.Cipher;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.*;
import java.util.Objects;/*** RSA加、解密工具** 1. 公钥负责加密,私钥负责解密;* 2. 私钥负责签名,公钥负责验证。*/
public class RsaUtil {/*** 数字签名,密钥算法*/public static final String RSA_ALGORITHM = "RSA";public static final String RSA_PADDING = "RSA/ECB/PKCS1Padding";/*** 获取 KeyPair** @return KeyPair*/public static KeyPair genKeyPair() {return genKeyPair(1024);}/*** 获取 KeyPair** @param keySize key size* @return KeyPair*/public static KeyPair genKeyPair(int keySize) {try {KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(RSA_ALGORITHM);// 密钥位数keyPairGen.initialize(keySize);// 密钥对return new KeyPair(keyPairGen.generateKeyPair());} catch (Exception e) {throw new RuntimeException(e);}}/*** 生成RSA私钥** @param modulus N特征值* @param exponent d特征值* @return {@link PrivateKey}*/public static PrivateKey generatePrivateKey(String modulus, String exponent) {return generatePrivateKey(new BigInteger(modulus), new BigInteger(exponent));}/*** 生成RSA私钥** @param modulus N特征值* @param exponent d特征值* @return {@link PrivateKey}*/public static PrivateKey generatePrivateKey(BigInteger modulus, BigInteger exponent) {RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(modulus, exponent);try {KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);return keyFactory.generatePrivate(keySpec);} catch (Exception e) {throw new RuntimeException(e);}}/*** 生成RSA公钥** @param modulus N特征值* @param exponent e特征值* @return {@link PublicKey}*/public static PublicKey generatePublicKey(String modulus, String exponent) {return generatePublicKey(new BigInteger(modulus), new BigInteger(exponent));}/*** 生成RSA公钥** @param modulus N特征值* @param exponent e特征值* @return {@link PublicKey}*/public static PublicKey generatePublicKey(BigInteger modulus, BigInteger exponent) {RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, exponent);try {KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);return keyFactory.generatePublic(keySpec);} catch (Exception e) {throw new RuntimeException(e);}}/*** 得到公钥** @param base64PubKey 密钥字符串(经过base64编码)* @return PublicKey*/public static PublicKey getPublicKey(String base64PubKey) {Objects.requireNonNull(base64PubKey, "base64 public key is null.");byte[] keyBytes = Base64Utils.decodeFromString(base64PubKey);X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);try {KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);return keyFactory.generatePublic(keySpec);} catch (Exception e) {throw new RuntimeException(e);}}/*** 得到公钥字符串** @param base64PubKey 密钥字符串(经过base64编码)* @return PublicKey String*/public static String getPublicKeyToBase64(String base64PubKey) {PublicKey publicKey = getPublicKey(base64PubKey);return getKeyString(publicKey);}/*** 得到私钥** @param base64PriKey 密钥字符串(经过base64编码)* @return PrivateKey*/public static PrivateKey getPrivateKey(String base64PriKey) {Objects.requireNonNull(base64PriKey, "base64 private key is null.");byte[] keyBytes = Base64Utils.decodeFromString(base64PriKey);PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);try {KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);return keyFactory.generatePrivate(keySpec);} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {throw new RuntimeException(e);}}/*** 得到密钥字符串(经过base64编码)** @param key key* @return base 64 编码后的 key*/public static String getKeyString(Key key) {return Base64Utils.encodeToString(key.getEncoded());}/*** 得到私钥 base64** @param base64PriKey 密钥字符串(经过base64编码)* @return PrivateKey String*/public static String getPrivateKeyToBase64(String base64PriKey) {PrivateKey privateKey = getPrivateKey(base64PriKey);return getKeyString(privateKey);}/*** 共要加密** @param base64PublicKey base64 的公钥* @param data 待加密的内容* @return 加密后的内容*/public static byte[] encrypt(String base64PublicKey, byte[] data) {return encrypt(getPublicKey(base64PublicKey), data);}/*** 共要加密** @param publicKey 公钥* @param data 待加密的内容* @return 加密后的内容*/public static byte[] encrypt(PublicKey publicKey, byte[] data) {return rsa(publicKey, data, Cipher.ENCRYPT_MODE);}/*** 私钥加密,用于 qpp 内,公钥解密** @param base64PrivateKey base64 的私钥* @param data 待加密的内容* @return 加密后的内容*/public static byte[] encryptByPrivateKey(String base64PrivateKey, byte[] data) {return encryptByPrivateKey(getPrivateKey(base64PrivateKey), data);}/*** 私钥加密,加密成 base64 字符串,用于 qpp 内,公钥解密** @param base64PrivateKey base64 的私钥* @param data 待加密的内容* @return 加密后的内容*/public static String encryptByPrivateKeyToBase64(String base64PrivateKey, byte[] data) {return Base64Utils.encodeToString(encryptByPrivateKey(base64PrivateKey, data));}/*** 私钥加密,用于 qpp 内,公钥解密** @param privateKey 私钥* @param data 待加密的内容* @return 加密后的内容*/public static byte[] encryptByPrivateKey(PrivateKey privateKey, byte[] data) {return rsa(privateKey, data, Cipher.ENCRYPT_MODE);}/*** 公钥加密** @param base64PublicKey base64 公钥* @param data 待加密的内容* @return 加密后的内容*/@Nullablepublic static String encryptToBase64(String base64PublicKey, @Nullable String data) {if (Func.isEmpty(data)) {return null;}return Base64Utils.encodeToString(encrypt(base64PublicKey, data.getBytes(StandardCharsets.UTF_8)));}/*** 解密** @param base64PrivateKey base64 私钥* @param data 数据* @return 解密后的数据*/public static byte[] decrypt(String base64PrivateKey, byte[] data) {return decrypt(getPrivateKey(base64PrivateKey), data);}/*** 解密** @param base64publicKey base64 公钥* @param data 数据* @return 解密后的数据*/public static byte[] decryptByPublicKey(String base64publicKey, byte[] data) {return decryptByPublicKey(getPublicKey(base64publicKey), data);}/*** 解密** @param privateKey privateKey* @param data 数据* @return 解密后的数据*/public static byte[] decrypt(PrivateKey privateKey, byte[] data) {return rsa(privateKey, data, Cipher.DECRYPT_MODE);}/*** 解密** @param publicKey PublicKey* @param data 数据* @return 解密后的数据*/public static byte[] decryptByPublicKey(PublicKey publicKey, byte[] data) {return rsa(publicKey, data, Cipher.DECRYPT_MODE);}/*** rsa 加、解密** @param key key* @param data 数据* @param mode 模式* @return 解密后的数据*/private static byte[] rsa(Key key, byte[] data, int mode) {try {Cipher cipher = Cipher.getInstance(RSA_PADDING);cipher.init(mode, key);return cipher.doFinal(data);} catch (Exception e) {throw new RuntimeException(e);}}/*** base64 数据解密** @param base64PublicKey base64 公钥* @param base64Data base64数据* @return 解密后的数据*/public static byte[] decryptByPublicKeyFromBase64(String base64PublicKey, byte[] base64Data) {return decryptByPublicKey(getPublicKey(base64PublicKey), base64Data);}/*** base64 数据解密** @param base64PrivateKey base64 私钥* @param base64Data base64数据* @return 解密后的数据*/@Nullablepublic static String decryptFromBase64(String base64PrivateKey, @Nullable String base64Data) {if (Func.isEmpty(base64Data)) {return null;}return new String(decrypt(base64PrivateKey, Base64Utils.decodeFromString(base64Data)), StandardCharsets.UTF_8);}/*** base64 数据解密** @param base64PrivateKey base64 私钥* @param base64Data base64数据* @return 解密后的数据*/public static byte[] decryptFromBase64(String base64PrivateKey, byte[] base64Data) {return decrypt(base64PrivateKey, Base64Utils.decode(base64Data));}/*** base64 数据解密** @param base64PublicKey base64 公钥* @param base64Data base64数据* @return 解密后的数据*/@Nullablepublic static String decryptByPublicKeyFromBase64(String base64PublicKey, @Nullable String base64Data) {if (Func.isEmpty(base64Data)) {return null;}return new String(decryptByPublicKeyFromBase64(base64PublicKey, Base64Utils.decodeFromString(base64Data)), StandardCharsets.UTF_8);}public static void main(String[] args) {
// KeyPair keyPair = genKeyPair();
// System.out.println("私钥:"+keyPair.getPrivateBase64());
// System.out.println("公钥:"+keyPair.getPublicBase64());String privateBase64 = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAImWaSqyYDbyu39uwEnaEMR29siUS+cnZ+DSCbX76tfFc0QG8bIKfCcPG/O2Owe1uii0B14HUPvcNV8IrMKPkt79a/bWWW+uIbVsB4zfNITLA8pDNb/nOELcE4N3Hy+4V7evUrG6ep1ceb/ru2cL9UxLzlca0IGRx8BcIlnI0TmtAgMBAAECgYBFSLLIx25f/Teh4jl+dws+g9GeC991FYjf06UEOUl3Qnza4sxPJayDVr5yqW9sYHzQBmg3V2PWkHtn0cx9ZSNF3iyDd0EQOb0ky9M7qWXifCD0uG1Ruc+cb1/vewRrj15VH2qOd9jmgeZhxWelvx0cENRpEMicIJ+zTt0kvX+UQQJBAMECqoBG5A5X3lkSdgsUbLtNbeIsPqH+FLA3+3UT29u+s5b9uPXhWBwVfRt3gtgJxaftiI/LHA7WZbFUYrKcxGUCQQC2fVxhNSFwTeiRCoimx+WID3fILOBNPNzGr75YzOzJdDpdnvHElo2CsUatoGDSk8S2hcUtwI2LSm/yxX9bzJepAkEAg/fYsIDIKe52fxyaTZUXizGz8jMiWAysBJkie7iqWSOZE6JDtwru/bTLp94dPq3f0aQd/YN4mcSKH6d9HHcH6QJAZrDOnkj2oyrEN3I1CZ0tNc52eid+pRgdqJTWyUOv74E/ItXBeP27bhLyEdxQ/851gLxwA9n6DKr7qiKnE3Ji2QJAMcs1ipl0n/aR0NR56/uI0R1cD2AsoimfZjc8hPWdjs/YfpZVQnrcpgQx5Ps4O631F7LQKz22MbwOoBt3UcZYSQ==";String publicBase64 = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJlmkqsmA28rt/bsBJ2hDEdvbIlEvnJ2fg0gm1++rXxXNEBvGyCnwnDxvztjsHtbootAdeB1D73DVfCKzCj5Le/Wv21llvriG1bAeM3zSEywPKQzW/5zhC3BODdx8vuFe3r1KxunqdXHm/67tnC/VMS85XGtCBkcfAXCJZyNE5rQIDAQAB";System.out.println("加密数据:"+encryptToBase64(publicBase64, "hello world"));System.out.println("解密数据:"+decryptFromBase64(privateBase64, encryptToBase64(publicBase64, "hello world")));String data = "hu5u8UyEg6fcn+/4wKFRSUVGETrXGifVE6/RzRBQCVxAQt+XMA7C+xVR6Ws2ZXFmYVFoS0YL29u6oVkxvmESdRc9Zj/bf0M6ykqa57vyvvRRmrrqCSYUD6STo/QRdPFK4sxlsseTU2/XjZQYohnrMmouYspWykJ3fcN34uoieHc=";
// System.out.println("解密数据:"+decryptFromBase64(privateBase64, data));System.out.println("解密数据:"+RsaUtil.decryptFromBase64(privateBase64, data));}}
3.16 SpringBootLearningApplication启动类
- 16.SpringBootLearningApplication
package com.learning;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;/****/
@SpringBootApplication
@ComponentScan(basePackages = {"com.learning"})
public class SpringBootLearningApplication {public static void main(String[] args) {SpringApplication.run(SpringBootLearningApplication.class, args);}
}
3.17 配置文件
- 17.application.yaml
api:crypto:# 私钥rsaPrivateKey: MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAImWaSqyYDbyu39uwEnaEMR29siUS+cnZ+DSCbX76tfFc0QG8bIKfCcPG/O2Owe1uii0B14HUPvcNV8IrMKPkt79a/bWWW+uIbVsB4zfNITLA8pDNb/nOELcE4N3Hy+4V7evUrG6ep1ceb/ru2cL9UxLzlca0IGRx8BcIlnI0TmtAgMBAAECgYBFSLLIx25f/Teh4jl+dws+g9GeC991FYjf06UEOUl3Qnza4sxPJayDVr5yqW9sYHzQBmg3V2PWkHtn0cx9ZSNF3iyDd0EQOb0ky9M7qWXifCD0uG1Ruc+cb1/vewRrj15VH2qOd9jmgeZhxWelvx0cENRpEMicIJ+zTt0kvX+UQQJBAMECqoBG5A5X3lkSdgsUbLtNbeIsPqH+FLA3+3UT29u+s5b9uPXhWBwVfRt3gtgJxaftiI/LHA7WZbFUYrKcxGUCQQC2fVxhNSFwTeiRCoimx+WID3fILOBNPNzGr75YzOzJdDpdnvHElo2CsUatoGDSk8S2hcUtwI2LSm/yxX9bzJepAkEAg/fYsIDIKe52fxyaTZUXizGz8jMiWAysBJkie7iqWSOZE6JDtwru/bTLp94dPq3f0aQd/YN4mcSKH6d9HHcH6QJAZrDOnkj2oyrEN3I1CZ0tNc52eid+pRgdqJTWyUOv74E/ItXBeP27bhLyEdxQ/851gLxwA9n6DKr7qiKnE3Ji2QJAMcs1ipl0n/aR0NR56/uI0R1cD2AsoimfZjc8hPWdjs/YfpZVQnrcpgQx5Ps4O631F7LQKz22MbwOoBt3UcZYSQ==
4. 调用截图




相关文章:
【java】前端RSA加密后端解密
目录 1. 说明2. 前端示例3. 后端示例3.1 pom依赖3.2 后端结构图3.3 DecryptHttpInputMessage3.4 ApiCryptoProperties3.5 TestController3.6 ApiCryptoUtil3.7 ApiDecryptParamResolver3.8 ApiDecryptRequestBodyAdvice3.9 ApiDecryptRsa3.10 ApiCryptoProperties3.11 KeyPair3…...
机器学习 | Scikit Learn中的普通最小二乘法和岭回归
在统计建模中,普通最小二乘法(OLS)和岭回归是两种广泛使用的线性回归分析技术。OLS是一种传统的方法,它通过最小化预测值和实际值之间的平方误差之和来找到数据的最佳拟合线。然而,OLS可以遭受高方差和过拟合时&#x…...
代码随想录冲冲冲 Day60 图论Part11
97. 小明逛公园 floyd算法 其实就是先用i和j拼成一个平面 然后看每次从i到j距离 这里分两种情况 1.中间没有经过别的点 2.中间有经过别的点 那么最小步数就要取这两个的最小值 所有根本逻辑是i j确定一个面 再通过不同的k去看每一个中间点 所以k要在最外层 上一次的值要…...
golang web笔记-1.创建Web Server和Handler请求
1. 创建http web server的两个方法 1.1. 方式一:http.ListenAndServe(addr string, handler Handler) addr string:监听地址,如果为"" ,那么就是所有网络接口的80接口handler Handler:如果为nil,那么就是D…...
【Python】Copier:高效的项目模板化工具
Copier 是一个开源的 Python 工具,用于基于项目模板快速生成新项目。它通过灵活的模板化系统,使开发者可以快速创建、维护和更新项目模板,从而自动化项目的初始化流程。无论是简单的文件复制,还是复杂的项目结构配置,C…...
Spring系列 BeanPostProcessor
文章目录 BeanPostProcessor注册时机执行时机 InstantiationAwareBeanPostProcessorSmartInstantiationAwareBeanPostProcessor 本文源码基于spring-beans-5.3.31 参考:https://docs.spring.io/spring-framework/reference/core/beans/factory-extension.html#beans…...
Qualitor processVariavel.php 未授权命令注入漏洞复现(CVE-2023-47253)
0x01 漏洞概述 Qualitor 8.20及之前版本存在命令注入漏洞,远程攻击者可利用该漏洞通过PHP代码执行任意代码。 0x02 复现环境 FOFA:app"Qualitor-Web" 0x03 漏洞复现 PoC GET /html/ad/adpesquisasql/request/processVariavel.php?gridValoresPopHi…...
SpringBoot的概述与搭建
目录 一.SpringBoot的概述 二.SpringBoot 特点 三.SpringBoot 的核心功能 3.1起步依赖 3.2自动配置 四.SpringBoot 开发环境构建 五.SpringBoot 配置文件 六.SpringBoot数据访问管理 七.springboot注解 八.springboot集成mybatis 九.springboot全局异常捕获与处理 一…...
视频集成与融合项目中需要视频编码,但是分辨率不兼容怎么办?
在众多视频整合项目中,一个显著的趋势是融合多元化的视频资源,以实现统一监管与灵活调度。这一需求促使项目团队不断探索新的集成方案,确保不同来源的视频流能够无缝对接,共同服务于统一的调看与管理平台,进而提升整体…...
kafka 换盘重平衡副本 操作流程
一、起因 kakfa某块数据盘损坏,且数据无法恢复,需清空换新盘 二、梳理操作流程 查看topic信息 sh ./kafka-topics --bootstrap-server ***:9092 --list --exclude-internal 查看某个topic数据分布情况 sh ./kafka-topics --bootstrap-server ***:…...
vue3.0 + element plus 全局自定义指令:select滚动分页
需求:项目里面下拉框数据较多 ,一次性请求数据,体验差,效果就是滚动进行分页。 看到这个需求的时候,我第一反应就是封装成自定义指令,这样回头用的时候,直接调用就可以了。 第一步 第二步&…...
HarmonyOS/OpenHarmony 离线加载web资源,并实现web资源更新
关键词:h5离线包加载、h5离线包更新、沙箱 在上一篇文章中,我们已经介绍了如何将 rawfile 资源文件中的文件数据拷贝到沙箱下,那么该篇文章将介绍如何加载该沙箱目录下的文件资源(此处以打包后的web资源为例)…...
【Spark 实战】基于spark3.4.2+iceberg1.6.1搭建本地调试环境
基于spark3.4.2iceberg1.6.1搭建本地调试环境 文章目录 基于spark3.4.2iceberg1.6.1搭建本地调试环境环境准备使用maven构建sparksql编辑SparkSQL简单任务附录A iceberg术语参考 环境准备 IntelliJ IDEA 2024.1.2 (Ultimate Edition)JDK 1.8Spark 3.4.2Iceberg 1.6.1 使用mave…...
TCP连接建立中不携带数据的报文段为何不消耗序号解析
在TCP协议中,序号的使用是为了确保数据能够按照正确的顺序被接收端重组和确认。每个TCP报文段都有一个序号字段,用于标识该报文段中数据的起始位置相对于整个数据流的偏移量。 初始序号和三次握手 在TCP连接的建立过程中,三次握手是确保双方…...
JS设计模式之状态模式:优雅地管理应用中产生的不同状态
一. 前言 在过去,我们经常使用条件语句(if-else 语句)来处理应用程序中的不同状态。然而,这种方式往往会让代码变得冗长、难以维护,并可能引入潜在的 bug。而状态模式则提供了一种更加结构化和可扩展的方法来处理状态…...
C语言系列4——指针与数组(1)
我们开始C语言的指针与数组 这部分开始进阶了,得反复学习 在开始正题之前,写说一下我们都知道当写一个函数的时候需要进行传参,当实参传递给形参的时候,形参是有独立空间的,那么数组传参又是怎么样的呢,我…...
JS网页设计案例
下面是一个简单的 JavaScript 网页设计案例,展示了如何使用 HTML、CSS 和 JavaScript 创建一个动态的网页。 案例:简单的待办事项列表 1. HTML 部分 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8…...
4.2.1 通过DTS传递物理中断号给Linux
点击查看系列文章 》 Interrupt Pipeline系列文章大纲-CSDN博客 4.2.1 通过DTS传递物理中断号给Linux 参考《GICv3_Software_Overview_Official_Release_B》,下表描述了GIC V3支持的INTID(硬件中断号)的范围。 SGI (Software Generated Interrupt):软…...
常用性能优化方法
在一个Java项目中进行性能优化是至关重要的。性能优化能够提高项目的效率和响应速度,提升用户体验,并且可以节省服务器资源和成本。 首先,性能优化可以确保项目的高效运行。当项目在运行时,性能问题可能会导致应用程序变慢、响应时…...
上海我店:创新模式引领本地生活新风尚
近年来,一个名为“上海我店”的新兴平台在网络空间中迅速崛起,其公布的业绩令人瞩目——在短短三年内,交易流水已跨越百亿大关,并在最近一个月内迎来了近百万的新增注册用户。这一强劲的增长势头,无疑吸引了众多商家和…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
4. TypeScript 类型推断与类型组合
一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。通过分析上下文和初始值,TypeSc…...
BLEU评分:机器翻译质量评估的黄金标准
BLEU评分:机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域,衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标,自2002年由IBM的Kishore Papineni等人提出以来,…...
苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会
在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...
嵌入式常见 CPU 架构
架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集,单周期执行;低功耗、CIP 独立外设;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel(原始…...
Kafka主题运维全指南:从基础配置到故障处理
#作者:张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1:主题删除失败。常见错误2:__consumer_offsets占用太多的磁盘。 主题日常管理 …...
