【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项目中进行性能优化是至关重要的。性能优化能够提高项目的效率和响应速度,提升用户体验,并且可以节省服务器资源和成本。 首先,性能优化可以确保项目的高效运行。当项目在运行时,性能问题可能会导致应用程序变慢、响应时…...
上海我店:创新模式引领本地生活新风尚
近年来,一个名为“上海我店”的新兴平台在网络空间中迅速崛起,其公布的业绩令人瞩目——在短短三年内,交易流水已跨越百亿大关,并在最近一个月内迎来了近百万的新增注册用户。这一强劲的增长势头,无疑吸引了众多商家和…...
【微服务】前端微服务qiankun 2.x主子应用通信代码片段
主应用代码 主应用工程里面源代码新建qiankun/index.js,通信代码如下: import { initGlobalState } from "qiankun"; import store from /store// 主应用与微应用数据通信 const state {subappClassName: // 设置子应用打包根的class类名 …...
高级java每日一道面试题-2024年9月30日-算法篇-LRU是什么?如何实现?
如果有遗漏,评论区告诉我进行补充 面试官: LRU是什么?如何实现? 我回答: LRU(Least Recently Used)是一种常用的缓存淘汰策略,用于在缓存满时决定哪些数据应该被移除。LRU算法的基本思想是:当缓存达到其容量上限时࿰…...
CSS选择器的全面解析与实战应用
CSS选择器的全面解析与实战应用 一、基本选择器1.1 通配符选择器(*)2.标签选择器(div)1.3 类名选择器(.class)4. id选择器(#id) 二、 属性选择器(attr)三、伪…...
vue3自动暴露element-plus组件的ref
自动暴露子组件的方法,注意在TS下,需要自己声明类型,我这里全用any代替了 <template><el-button click"getFocus">获得焦点</el-button><com ref"comRef" /> </template><script setup…...
龙芯+FreeRTOS+LVGL实战笔记(新)——10蜂鸣器嘀嘀嘀
本专栏是笔者另一个专栏《龙芯+RT-Thread+LVGL实战笔记》的姊妹篇,主要的区别在于实时操作系统的不同,章节的安排和任务的推进保持一致,并对源码做了完善与优化,各位可以先到本人主页下去浏览另一专栏的博客列表(目前已撰写36篇,图1所示),再决定是否订阅。此外,也可以…...
微信小程序-数据模型与动态赋值
首先新建一个小程序项目. 这边有创建基础项目的流程:从0新建一个微信小程序实现一个简单跳转_小白开发小程序源代码-CSDN博客 一共两步: 1.建立页面的 数据模型 和 默认赋值: 默认赋值: 2.接收输入框的新文案,动态替换上面的文案展示 //文件 testUI.js增加方法:onInputChan…...
【Redis】Linux下安装配置及通过C++访问Redis
文章目录 一、Linux Centos 7.0版本下的安装及配置二、通过C访问Redis 一、Linux Centos 7.0版本下的安装及配置 通过源来安装,此次安装的版本为 redis 5.0 的,要通过其他源进行安装,首先安装 scl 源 yum install centos-release-scl-rh再安…...
Python 入门教程(4)数据类型 | 4.7、元组
文章目录 一、元组1、定义2、创建3、访问元组元素4、遍历元组5、 前言: 在Python编程中,元组(tuple)是一种内置的数据结构,它提供了一种存储多个项目(元素)的方式,这些项目可以是不同…...
Temu正在吸引越来越多的亚马逊卖家,这个市场Temu蝉联下载榜首
近年来,全球电商市场竞争愈发激烈,各大平台纷纷使出浑身解数,以期在激烈的市场竞争中脱颖而出。 一个来自中国的新兴电商平台——Temu,凭借其独特的市场策略和迅猛的发展势头,正在吸引越来越多的亚马逊卖家。Temu为美国…...
设计原则模式概览
前言 架构设计是软件系统稳定的核心因素,也是程序员晋级架构师的核心因素,建议日常开发过程中针对设计进行深挖与思考 核心 分清楚哪些是稳定的,哪些是变化的(一定有稳定跟变化的成分); 捋清楚哪些是类设计…...
12306网站很难做吗/广告网站留电话不用验证码
1 doctype写完整<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 IE请使用标准模式转载于:https://www.cnblogs.com/sunzhihua/p/8425282.html...
dephi 网站开发/免费com域名注册网站
转载于:https://www.cnblogs.com/arci/p/11030173.html...
在线建设房屋设计网站/360搜索引擎首页
2019独角兽企业重金招聘Python工程师标准>>> 如果说用“永存、曲折、已死、重生”来形容Java,笔者以为一点也不为过。 1991年,James Gosling带领着名为“Green Team”的团队着手研发一种新的语言以及专为下一代数字设备和计算机使用的网络系统…...
mugeda做网站/百度搜索风云榜
实验十 团队作业6-团队项目系统设计改进与详细设计 项目内容这个作业属于哪个课程http://www.cnblogs.com/nwnu-daizh/这个作业的要求在哪里https://www.cnblogs.com/nwnu-daizh/p/10946673.html团队名称坐热板凳组作业学习目标①掌握面向对象软件设计方法;②完善系…...
专业网站建设搭建/广州市口碑seo推广
打印机用久了难免会出现故障,在打印过程中可能会遇到各种各样的迷惑行为,比如:打印乱码、条纹、黑点、阴影等。今天小编就来给大家说说激光打印机的迷惑行为:打印一半如何解决。原图打印一半01检查打印机 检查打印机查看是否是打印…...
vs做asp网站流程/搜索引擎哪个最好用
本文为芬兰坦佩雷大学(作者:Murat Pojon)的硕士论文,共39页。 本文研究了机器学习算法在预测学生是否成功方面的应用。本文的重点是比较机器学习方法和特征工程技术在多大程度上提高了预测性能,采用了三种不同的机器学…...