'创建'
This commit is contained in:
commit
d4e116d41f
70
service/pom.xml
Normal file
70
service/pom.xml
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>2.6.1</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
<groupId>com.pnkx</groupId>
|
||||||
|
<artifactId>service</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<url>https://maven.aliyun.com/nexus/content/groups/public</url>
|
||||||
|
<name>service</name>
|
||||||
|
<description>service</description>
|
||||||
|
<properties>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<!--sm3,sm4加密算法-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcprov-jdk15on</artifactId>
|
||||||
|
<version>1.69</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 阿里JSON解析器 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>fastjson</artifactId>
|
||||||
|
<version>1.2.78</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-devtools</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.pnkx.service;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class ServiceApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(ServiceApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package com.pnkx.service.controller;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author by PHY
|
||||||
|
* @classname TestController
|
||||||
|
* @date 2021-12-15 15:11
|
||||||
|
* @description: 描述
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/test")
|
||||||
|
public class TestController {
|
||||||
|
|
||||||
|
@GetMapping("getRequest")
|
||||||
|
public Object getRequest(@RequestParam Map<String, Object> params) {
|
||||||
|
System.out.println(params.toString());
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("postRequest")
|
||||||
|
public Object postRequest(@RequestBody Map<String, Object> params) {
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,94 @@
|
|||||||
|
package com.pnkx.service.filter;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.pnkx.service.filter.domain.WrappedRequest;
|
||||||
|
import com.pnkx.service.filter.domain.WrappedResponse;
|
||||||
|
import com.pnkx.service.utils.SM2Utils;
|
||||||
|
import com.pnkx.service.utils.SM4Utils;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author by PHY
|
||||||
|
* @classname encryptionFilter
|
||||||
|
* @date 2021-12-15 16:27
|
||||||
|
* @description: 描述
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class EncryptionFilter extends OncePerRequestFilter{
|
||||||
|
|
||||||
|
/** get请求关键字 */
|
||||||
|
private static final String GET = "GET";
|
||||||
|
/** 是否开启解密 */
|
||||||
|
@Value("${encrypt.enabled}")
|
||||||
|
private Boolean encryptEnabled;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
|
||||||
|
// 解密
|
||||||
|
if (encryptEnabled && !GET.equals(request.getMethod())) {
|
||||||
|
String requestKey = request.getHeader("RequestKey");
|
||||||
|
String decrypt = SM2Utils.decrypt(requestKey);
|
||||||
|
String sm4Key = decrypt.split("-")[1];
|
||||||
|
String requestBody = getRequestBody(request);
|
||||||
|
String requestBodyMw = null;
|
||||||
|
Map<String, String> requestBodyMap = (Map<String, String>) JSON.parse(requestBody);
|
||||||
|
// 解密请求报文
|
||||||
|
if (!"".equals(requestBody)) {
|
||||||
|
try {
|
||||||
|
requestBodyMw = SM4Utils.decryptEcb(sm4Key, requestBodyMap.get("cis_req_params"));
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request = new WrappedRequest(request, requestBodyMw);
|
||||||
|
// 加密返回值
|
||||||
|
WrappedResponse wrapResponse = new WrappedResponse(response);
|
||||||
|
chain.doFilter(request, wrapResponse);
|
||||||
|
String content = wrapResponse.getContent();
|
||||||
|
String responseBodyMw = null;
|
||||||
|
try {
|
||||||
|
// 加密
|
||||||
|
responseBodyMw = SM4Utils.encryptEcb(sm4Key, content);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
response.setContentLength(-1);
|
||||||
|
PrintWriter out = response.getWriter();
|
||||||
|
out.write(responseBodyMw);
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取body体内容
|
||||||
|
* @param req 请求
|
||||||
|
* @return body体内容
|
||||||
|
*/
|
||||||
|
private String getRequestBody(HttpServletRequest req) {
|
||||||
|
try {
|
||||||
|
BufferedReader reader = req.getReader();
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
String line = null;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
sb.append(line);
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
package com.pnkx.service.filter.domain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author PHY
|
||||||
|
* @classname WrappedRequest
|
||||||
|
* @data 2021/10/29 12:58
|
||||||
|
* @description 描述
|
||||||
|
*/
|
||||||
|
|
||||||
|
import javax.servlet.ReadListener;
|
||||||
|
import javax.servlet.ServletInputStream;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletRequestWrapper;
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
public class WrappedRequest extends HttpServletRequestWrapper {
|
||||||
|
|
||||||
|
private String requestBody = null;
|
||||||
|
HttpServletRequest req = null;
|
||||||
|
|
||||||
|
public WrappedRequest(HttpServletRequest request) {
|
||||||
|
super(request);
|
||||||
|
this.req = request;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WrappedRequest(HttpServletRequest request, String requestBody) {
|
||||||
|
super(request);
|
||||||
|
this.requestBody = requestBody;
|
||||||
|
this.req = request;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see javax.servlet.ServletRequestWrapper#getReader()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public BufferedReader getReader() throws IOException {
|
||||||
|
return new BufferedReader(new StringReader(requestBody));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see javax.servlet.ServletRequestWrapper#getInputStream()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ServletInputStream getInputStream() throws IOException {
|
||||||
|
return new ServletInputStream() {
|
||||||
|
private InputStream in = new ByteArrayInputStream(
|
||||||
|
requestBody.getBytes(req.getCharacterEncoding()));
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read() throws IOException {
|
||||||
|
return in.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFinished() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isReady() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setReadListener(ReadListener readListener) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
package com.pnkx.service.filter.domain;
|
||||||
|
|
||||||
|
import javax.servlet.ServletOutputStream;
|
||||||
|
import javax.servlet.WriteListener;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.servlet.http.HttpServletResponseWrapper;
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author PHY
|
||||||
|
* @classname WrappedResponse
|
||||||
|
* @data 2021/10/29 12:59
|
||||||
|
* @description 描述
|
||||||
|
*/
|
||||||
|
public class WrappedResponse extends HttpServletResponseWrapper {
|
||||||
|
|
||||||
|
private ByteArrayOutputStream buffer = null;
|
||||||
|
private ServletOutputStream out = null;
|
||||||
|
private PrintWriter writer = null;
|
||||||
|
|
||||||
|
public WrappedResponse(HttpServletResponse resp) throws IOException {
|
||||||
|
super(resp);
|
||||||
|
// 真正存储数据的流
|
||||||
|
buffer = new ByteArrayOutputStream();
|
||||||
|
out = new WapperedOutputStream(buffer);
|
||||||
|
writer = new PrintWriter(new OutputStreamWriter(buffer,
|
||||||
|
this.getCharacterEncoding()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重载父类获取outputStream的方法 */
|
||||||
|
@Override
|
||||||
|
public ServletOutputStream getOutputStream() throws IOException {
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重载父类获取writer的方法 */
|
||||||
|
@Override
|
||||||
|
public PrintWriter getWriter() throws UnsupportedEncodingException {
|
||||||
|
return writer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重载父类获取flushBuffer的方法 */
|
||||||
|
@Override
|
||||||
|
public void flushBuffer() throws IOException {
|
||||||
|
if (out != null) {
|
||||||
|
out.flush();
|
||||||
|
}
|
||||||
|
if (writer != null) {
|
||||||
|
writer.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
buffer.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 将out、writer中的数据强制输出到WapperedResponse的buffer里面,否则取不到数据 */
|
||||||
|
public byte[] getResponseData() throws IOException {
|
||||||
|
flushBuffer();
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContent() throws IOException {
|
||||||
|
flushBuffer();//将out、writer中的数据强制输出到WapperedResponse的buffer里面,否则取不到数据
|
||||||
|
return new String(buffer.toByteArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 内部类,对ServletOutputStream进行包装 */
|
||||||
|
private class WapperedOutputStream extends ServletOutputStream {
|
||||||
|
private ByteArrayOutputStream bos = null;
|
||||||
|
|
||||||
|
public WapperedOutputStream(ByteArrayOutputStream stream)
|
||||||
|
throws IOException {
|
||||||
|
bos = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(int b) throws IOException {
|
||||||
|
bos.write(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] b) throws IOException {
|
||||||
|
bos.write(b, 0, b.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isReady() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setWriteListener(WriteListener writeListener) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
56
service/src/main/java/com/pnkx/service/utils/SM2Utils.java
Normal file
56
service/src/main/java/com/pnkx/service/utils/SM2Utils.java
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package com.pnkx.service.utils;
|
||||||
|
|
||||||
|
import org.bouncycastle.asn1.gm.GMNamedCurves;
|
||||||
|
import org.bouncycastle.asn1.x9.X9ECParameters;
|
||||||
|
import org.bouncycastle.crypto.InvalidCipherTextException;
|
||||||
|
import org.bouncycastle.crypto.engines.SM2Engine;
|
||||||
|
import org.bouncycastle.crypto.params.ECDomainParameters;
|
||||||
|
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
||||||
|
import org.bouncycastle.util.encoders.Hex;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author PHY
|
||||||
|
* @classname SM2Util
|
||||||
|
* @data 2021/11/1 10:31
|
||||||
|
* @description SM2工具类
|
||||||
|
*/
|
||||||
|
public class SM2Utils {
|
||||||
|
/** 私钥 */
|
||||||
|
private static final String privateKey = "a2081b5b81fbea0b6b973a3ab6dbbbc65b1164488bf22d8ae2ff0b8260f64853";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解密
|
||||||
|
* @param ciphertext 密文
|
||||||
|
* @return 明文
|
||||||
|
*/
|
||||||
|
public static String decrypt(String ciphertext) {
|
||||||
|
X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
|
||||||
|
ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
|
||||||
|
byte[] cipherData = ciphertext.getBytes(StandardCharsets.UTF_8);
|
||||||
|
byte[] cipherDataByte = Hex.decode(cipherData);
|
||||||
|
//刚才的私钥Hex,先还原私钥
|
||||||
|
BigInteger privateKeyD = new BigInteger(privateKey, 16);
|
||||||
|
ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters);
|
||||||
|
|
||||||
|
//用私钥解密
|
||||||
|
SM2Engine sm2Engine = new SM2Engine();
|
||||||
|
sm2Engine.init(false, privateKeyParameters);
|
||||||
|
|
||||||
|
//processBlock得到Base64格式,记得解码
|
||||||
|
byte[] arrayOfBytes = new byte[0];
|
||||||
|
try {
|
||||||
|
arrayOfBytes = Base64.getDecoder().decode(sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length));
|
||||||
|
} catch (InvalidCipherTextException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
//得到明文:SM2 Encryption Test
|
||||||
|
String data = new String(arrayOfBytes);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
179
service/src/main/java/com/pnkx/service/utils/SM4Utils.java
Normal file
179
service/src/main/java/com/pnkx/service/utils/SM4Utils.java
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
package com.pnkx.service.utils;
|
||||||
|
|
||||||
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
|
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.KeyGenerator;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import java.security.Key;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.security.Security;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @classname Sm4Util
|
||||||
|
* @data 2021-10-28 14:49:10
|
||||||
|
* @author PHY
|
||||||
|
* @description sm4加密算法工具类
|
||||||
|
*/
|
||||||
|
public class SM4Utils {
|
||||||
|
static {
|
||||||
|
Security.addProvider(new BouncyCastleProvider());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String ENCODING = "UTF-8";
|
||||||
|
public static final String ALGORITHM_NAME = "SM4";
|
||||||
|
/** 加密算法/分组加密模式/分组填充方式
|
||||||
|
* PKCS5Padding-以8个字节为一组进行分组加密
|
||||||
|
* 定义分组加密模式使用:PKCS5Padding
|
||||||
|
*/
|
||||||
|
public static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS5Padding";
|
||||||
|
/** 128-32位16进制;256-64位16进制 */
|
||||||
|
public static final int DEFAULT_KEY_SIZE = 128;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成ECB暗号
|
||||||
|
* @explain ECB模式(电子密码本模式:Electronic codebook)
|
||||||
|
* @param algorithmName
|
||||||
|
* 算法名称
|
||||||
|
* @param mode
|
||||||
|
* 模式
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private static Cipher generateEcbCipher(String algorithmName, int mode, byte[] key) throws Exception {
|
||||||
|
Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);
|
||||||
|
Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME);
|
||||||
|
cipher.init(mode, sm4Key);
|
||||||
|
return cipher;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p> 第一步:产生密钥</p>
|
||||||
|
* <p> 方式一:系统生成密钥</p>
|
||||||
|
* 自动生成密钥
|
||||||
|
* @explain
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static byte[] generateKey() throws Exception {
|
||||||
|
return generateKey(DEFAULT_KEY_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @explain
|
||||||
|
* @param keySize
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static byte[] generateKey(int keySize) throws Exception {
|
||||||
|
KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME);
|
||||||
|
kg.init(keySize, new SecureRandom());
|
||||||
|
return kg.generateKey().getEncoded();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p> 方法二:自己提供16进制的密钥</p>
|
||||||
|
* <p> 第二步:加密</p>
|
||||||
|
* sm4加密
|
||||||
|
* @explain 加密模式:ECB
|
||||||
|
* 密文长度不固定,会随着被加密字符串长度的变化而变化
|
||||||
|
* @param hexKey
|
||||||
|
* 16进制密钥(忽略大小写)
|
||||||
|
* @param paramStr
|
||||||
|
* 待加密字符串
|
||||||
|
* @return 返回16进制的加密字符串
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static String encryptEcb(String hexKey, String paramStr) throws Exception {
|
||||||
|
String cipherText = "";
|
||||||
|
// 16进制字符串-->byte[]
|
||||||
|
byte[] keyData = ByteUtils.fromHexString(hexKey);
|
||||||
|
// String-->byte[]
|
||||||
|
byte[] srcData = paramStr.getBytes(ENCODING);
|
||||||
|
// 加密后的数组
|
||||||
|
byte[] cipherArray = encrypt_Ecb_Padding(keyData, srcData);
|
||||||
|
// byte[]-->hexString
|
||||||
|
cipherText = ByteUtils.toHexString(cipherArray);
|
||||||
|
return cipherText;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密模式之Ecb
|
||||||
|
* @explain
|
||||||
|
* @param key
|
||||||
|
* @param data
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static byte[] encrypt_Ecb_Padding(byte[] key, byte[] data) throws Exception {
|
||||||
|
Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.ENCRYPT_MODE, key);
|
||||||
|
return cipher.doFinal(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sm4解密
|
||||||
|
* @explain 解密模式:采用ECB
|
||||||
|
* @param hexKey
|
||||||
|
* 16进制密钥
|
||||||
|
* @param cipherText
|
||||||
|
* 16进制的加密字符串(忽略大小写)
|
||||||
|
* @return 解密后的字符串
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static String decryptEcb(String hexKey, String cipherText) throws Exception {
|
||||||
|
// 用于接收解密后的字符串
|
||||||
|
String decryptStr = "";
|
||||||
|
// hexString-->byte[]
|
||||||
|
byte[] keyData = ByteUtils.fromHexString(hexKey);
|
||||||
|
// hexString-->byte[]
|
||||||
|
byte[] cipherData = ByteUtils.fromHexString(cipherText);
|
||||||
|
// 解密
|
||||||
|
byte[] srcData = decrypt_Ecb_Padding(keyData, cipherData);
|
||||||
|
// byte[]-->String
|
||||||
|
decryptStr = new String(srcData, ENCODING);
|
||||||
|
return decryptStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解密
|
||||||
|
* @explain
|
||||||
|
* @param key
|
||||||
|
* @param cipherText
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static byte[] decrypt_Ecb_Padding(byte[] key, byte[] cipherText) throws Exception {
|
||||||
|
Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.DECRYPT_MODE, key);
|
||||||
|
return cipher.doFinal(cipherText);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验加密前后的字符串是否为同一数据
|
||||||
|
* @explain
|
||||||
|
* @param hexKey
|
||||||
|
* 16进制密钥(忽略大小写)
|
||||||
|
* @param cipherText
|
||||||
|
* 16进制加密后的字符串
|
||||||
|
* @param paramStr
|
||||||
|
* 加密前的字符串
|
||||||
|
* @return 是否为同一数据
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static boolean verifyEcb(String hexKey, String cipherText, String paramStr) throws Exception {
|
||||||
|
// 用于接收校验结果
|
||||||
|
boolean flag = false;
|
||||||
|
// hexString-->byte[]
|
||||||
|
byte[] keyData = ByteUtils.fromHexString(hexKey);
|
||||||
|
// 将16进制字符串转换成数组
|
||||||
|
byte[] cipherData = ByteUtils.fromHexString(cipherText);
|
||||||
|
// 解密
|
||||||
|
byte[] decryptData = decrypt_Ecb_Padding(keyData, cipherData);
|
||||||
|
// 将原字符串转换成byte[]
|
||||||
|
byte[] srcData = paramStr.getBytes(ENCODING);
|
||||||
|
// 判断2个数组是否一致
|
||||||
|
flag = Arrays.equals(decryptData, srcData);
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
}
|
7
service/src/main/resources/application.yml
Normal file
7
service/src/main/resources/application.yml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# 端口号
|
||||||
|
server:
|
||||||
|
port: 8686
|
||||||
|
|
||||||
|
# 是否开启加密
|
||||||
|
encrypt:
|
||||||
|
enabled: true
|
3
web/.browserslistrc
Normal file
3
web/.browserslistrc
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
> 1%
|
||||||
|
last 2 versions
|
||||||
|
not dead
|
5
web/.editorconfig
Normal file
5
web/.editorconfig
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[*.{js,jsx,ts,tsx,vue}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
4
web/.env.development
Normal file
4
web/.env.development
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
VUE_APP_BASE_API = '/dev-api'
|
||||||
|
|
||||||
|
# 路由懒加载
|
||||||
|
VUE_CLI_BABEL_TRANSPILE_MODULES = true
|
1
web/.env.production
Normal file
1
web/.env.production
Normal file
@ -0,0 +1 @@
|
|||||||
|
VUE_APP_BASE_API = '/prod-api'
|
17
web/.eslintrc.js
Normal file
17
web/.eslintrc.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
env: {
|
||||||
|
node: true
|
||||||
|
},
|
||||||
|
extends: [
|
||||||
|
'plugin:vue/essential',
|
||||||
|
'@vue/standard'
|
||||||
|
],
|
||||||
|
parserOptions: {
|
||||||
|
parser: 'babel-eslint'
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||||
|
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
|
||||||
|
}
|
||||||
|
}
|
23
web/.gitignore
vendored
Normal file
23
web/.gitignore
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
/dist
|
||||||
|
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
5
web/babel.config.js
Normal file
5
web/babel.config.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
'@vue/cli-plugin-babel/preset'
|
||||||
|
]
|
||||||
|
}
|
40
web/package.json
Normal file
40
web/package.json
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"name": "code",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"serve": "vue-cli-service serve",
|
||||||
|
"build": "vue-cli-service build",
|
||||||
|
"lint": "vue-cli-service lint",
|
||||||
|
"start": "node index.js",
|
||||||
|
"server": "nodemon index.js --ignore client"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^0.24.0",
|
||||||
|
"core-js": "^3.6.5",
|
||||||
|
"element-ui": "^2.13.2",
|
||||||
|
"es6-promise": "^4.2.8",
|
||||||
|
"sm-crypto": "^0.3.7",
|
||||||
|
"vue": "^2.6.11",
|
||||||
|
"vue-router": "^3.2.0",
|
||||||
|
"vuex": "^3.4.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vue/cli-plugin-babel": "~4.5.0",
|
||||||
|
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||||
|
"@vue/cli-plugin-router": "~4.5.0",
|
||||||
|
"@vue/cli-plugin-vuex": "~4.5.0",
|
||||||
|
"@vue/cli-service": "~4.5.0",
|
||||||
|
"@vue/eslint-config-standard": "^5.1.2",
|
||||||
|
"babel-eslint": "^10.1.0",
|
||||||
|
"eslint": "^6.7.2",
|
||||||
|
"eslint-plugin-import": "^2.20.2",
|
||||||
|
"eslint-plugin-node": "^11.1.0",
|
||||||
|
"eslint-plugin-promise": "^4.2.1",
|
||||||
|
"eslint-plugin-standard": "^4.0.0",
|
||||||
|
"eslint-plugin-vue": "^6.2.2",
|
||||||
|
"less": "^3.0.4",
|
||||||
|
"less-loader": "^5.0.0",
|
||||||
|
"vue-template-compiler": "^2.6.11"
|
||||||
|
}
|
||||||
|
}
|
BIN
web/public/favicon.ico
Normal file
BIN
web/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
20
web/public/index.html
Normal file
20
web/public/index.html
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
|
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||||
|
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||||
|
<script src="js/crypto-js.js"></script>
|
||||||
|
<script src="js/sm2.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<noscript>
|
||||||
|
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
|
||||||
|
Please enable it to continue.</strong>
|
||||||
|
</noscript>
|
||||||
|
<div id="app"></div>
|
||||||
|
<!-- built files will be auto injected -->
|
||||||
|
</body>
|
||||||
|
</html>
|
1622
web/public/js/crypto-js.js
Normal file
1622
web/public/js/crypto-js.js
Normal file
File diff suppressed because it is too large
Load Diff
3953
web/public/js/sm2.js
Normal file
3953
web/public/js/sm2.js
Normal file
File diff suppressed because it is too large
Load Diff
9
web/src/App.vue
Normal file
9
web/src/App.vue
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<template>
|
||||||
|
<div id="app">
|
||||||
|
<router-view/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
|
||||||
|
</style>
|
23
web/src/api/index.js
Normal file
23
web/src/api/index.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get请求接口
|
||||||
|
*/
|
||||||
|
export function getRequest (data) {
|
||||||
|
return request({
|
||||||
|
url: '/test/getRequest',
|
||||||
|
method: 'get',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get请求接口
|
||||||
|
*/
|
||||||
|
export function postRequest (data) {
|
||||||
|
return request({
|
||||||
|
url: '/test/postRequest',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
BIN
web/src/assets/logo.png
Normal file
BIN
web/src/assets/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.7 KiB |
14
web/src/main.js
Normal file
14
web/src/main.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import Vue from 'vue';
|
||||||
|
import App from './App.vue';
|
||||||
|
import router from './router';
|
||||||
|
import store from './store';
|
||||||
|
import ElementUI from 'element-ui';
|
||||||
|
import 'element-ui/lib/theme-chalk/index.css';
|
||||||
|
Vue.use(ElementUI);
|
||||||
|
Vue.config.productionTip = false
|
||||||
|
|
||||||
|
new Vue({
|
||||||
|
router,
|
||||||
|
store,
|
||||||
|
render: h => h(App)
|
||||||
|
}).$mount('#app')
|
34
web/src/router/index.js
Normal file
34
web/src/router/index.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import VueRouter from 'vue-router'
|
||||||
|
|
||||||
|
Vue.use(VueRouter)
|
||||||
|
|
||||||
|
const routes = [
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
name: 'index',
|
||||||
|
component: () => import('../views/Index')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const router = new VueRouter({
|
||||||
|
routes
|
||||||
|
})
|
||||||
|
|
||||||
|
// 导航守卫
|
||||||
|
// 使用 router.beforeEach 注册一个全局前置守卫,判断用户是否登陆
|
||||||
|
router.beforeEach((to, from, next) => {
|
||||||
|
if (to.path === '/login') {
|
||||||
|
next();
|
||||||
|
} else {
|
||||||
|
let token = localStorage.getItem('Authorization');
|
||||||
|
|
||||||
|
if (token === 'null' || token === '') {
|
||||||
|
next('/login');
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router
|
15
web/src/store/index.js
Normal file
15
web/src/store/index.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import Vuex from 'vuex'
|
||||||
|
|
||||||
|
Vue.use(Vuex)
|
||||||
|
|
||||||
|
export default new Vuex.Store({
|
||||||
|
state: {
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
},
|
||||||
|
modules: {
|
||||||
|
}
|
||||||
|
})
|
102
web/src/utils/request.js
Normal file
102
web/src/utils/request.js
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
import {
|
||||||
|
sm4KeyGenerator,
|
||||||
|
getRequestKey,
|
||||||
|
encryptRequestData,
|
||||||
|
getResponseJson
|
||||||
|
} from '@/utils/sm'
|
||||||
|
|
||||||
|
// sm4秘钥
|
||||||
|
const sm4Key = sm4KeyGenerator()
|
||||||
|
// 是否加密
|
||||||
|
const isAddSm = true
|
||||||
|
// sm4Key数组
|
||||||
|
const sm4KeyArr = []
|
||||||
|
|
||||||
|
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
|
||||||
|
// 创建axios实例
|
||||||
|
const service = axios.create({
|
||||||
|
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||||
|
baseURL: process.env.VUE_APP_BASE_API,
|
||||||
|
// 超时
|
||||||
|
timeout: 10000
|
||||||
|
})
|
||||||
|
// request拦截器
|
||||||
|
service.interceptors.request.use(config => {
|
||||||
|
// 将秘钥加密后放到请求头中
|
||||||
|
config.headers.RequestKey = getRequestKey(sm4Key, false) // 请求key
|
||||||
|
// get请求映射params参数
|
||||||
|
if (config.method === 'get' && config.params) {
|
||||||
|
let url = config.url + '?'
|
||||||
|
for (const propName of Object.keys(config.params)) {
|
||||||
|
const value = config.params[propName]
|
||||||
|
const part = encodeURIComponent(propName) + '='
|
||||||
|
if (value !== null && typeof (value) !== 'undefined') {
|
||||||
|
if (typeof value === 'object') {
|
||||||
|
for (const key of Object.keys(value)) {
|
||||||
|
const params = propName + '[' + key + ']'
|
||||||
|
const subPart = encodeURIComponent(params) + '='
|
||||||
|
url += subPart + encodeURIComponent(value[key]) + '&'
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
url += part + encodeURIComponent(value) + '&'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
url = url.slice(0, -1)
|
||||||
|
config.params = {}
|
||||||
|
config.url = url
|
||||||
|
} else if (config.method === 'post') {
|
||||||
|
if (isAddSm && config.url.indexOf('upload') === -1) {
|
||||||
|
config.data = encryptRequestData(config.data, sm4Key, config.method)
|
||||||
|
const obj = {}
|
||||||
|
obj.url = config.url
|
||||||
|
obj.sm4keyNum = sm4Key
|
||||||
|
obj.cis_req_params = config.data.cis_req_params
|
||||||
|
sm4KeyArr.push(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return config
|
||||||
|
}, error => {
|
||||||
|
console.log(error)
|
||||||
|
Promise.reject(error)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 响应拦截器
|
||||||
|
service.interceptors.response.use(res => {
|
||||||
|
// 未设置状态码则默认成功状态
|
||||||
|
const code = res.data.code || 200
|
||||||
|
// 返回值解密
|
||||||
|
if (isAddSm) {
|
||||||
|
if (res.config.method !== 'OPTIONS') {
|
||||||
|
let i
|
||||||
|
let myKey
|
||||||
|
if (res.config.method === 'post') {
|
||||||
|
for (const item in sm4KeyArr) {
|
||||||
|
if (sm4KeyArr[item].cis_req_params === JSON.parse(res.config.data).cis_req_params) {
|
||||||
|
myKey = sm4KeyArr[item].sm4keyNum
|
||||||
|
i = item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (code === 200) {
|
||||||
|
res.data = getResponseJson(res.data, myKey)
|
||||||
|
}
|
||||||
|
sm4KeyArr.splice(i, 1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (code !== 200) {
|
||||||
|
// eslint-disable-next-line prefer-promise-reject-errors
|
||||||
|
return Promise.reject('error')
|
||||||
|
} else {
|
||||||
|
return res.data
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.log('err' + error)
|
||||||
|
return Promise.reject(error)
|
||||||
|
})
|
||||||
|
|
||||||
|
export default service
|
87
web/src/utils/sm.js
Normal file
87
web/src/utils/sm.js
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
// 引入sm
|
||||||
|
const sm = require('sm-crypto')
|
||||||
|
|
||||||
|
// sm2公钥
|
||||||
|
const sm2Key = '04813d4d97ad31bd9d18d785f337f683233099d5abed09cb397152d50ac28cc0ba43711960e811d90453db5f5a9518d660858a8d0c57e359a8bf83427760ebcbba'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成SMKey
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
export function sm4KeyGenerator () {
|
||||||
|
const sm4KeySeed = '123456789abcdef'
|
||||||
|
const keySize = 32
|
||||||
|
let sm4key = ''
|
||||||
|
while (sm4key.length < keySize) {
|
||||||
|
const randomIndex = Math.floor(Math.random() * 100) % 16
|
||||||
|
sm4key += sm4KeySeed.charAt(randomIndex)
|
||||||
|
}
|
||||||
|
return sm4key
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成SM2随机请求Key
|
||||||
|
* @param sm4key
|
||||||
|
* @param isStream
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export function getRequestKey (sm4key, isStream) {
|
||||||
|
let key = sm4key + '-' + Date.now()
|
||||||
|
if (isStream) {
|
||||||
|
key = '1-' + key
|
||||||
|
} else {
|
||||||
|
key = '0-' + key
|
||||||
|
}
|
||||||
|
// 1 - C1C3C2,0 - C1C2C3,默认为1
|
||||||
|
const cipherMode = 0
|
||||||
|
// 解密结果
|
||||||
|
// sm.sm2.doDecrypt(sm.sm2.doEncrypt(key, publicKey, cipherMode), privateKey, cipherMode);
|
||||||
|
// 加密结果
|
||||||
|
return sm2Encrypt(key, sm2Key, cipherMode)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对请求参数加密
|
||||||
|
* */
|
||||||
|
export function encryptRequestData (data, sm4key, type) {
|
||||||
|
let params
|
||||||
|
let obj
|
||||||
|
if (!data) {
|
||||||
|
if (type === 'get') {
|
||||||
|
params = 'tp=' + Date.now()
|
||||||
|
} else {
|
||||||
|
data = {
|
||||||
|
tp: Date.now()
|
||||||
|
}
|
||||||
|
params = JSON.stringify(data)
|
||||||
|
}
|
||||||
|
obj = {
|
||||||
|
cis_req_params: sm.sm4.encrypt(params, sm4key),
|
||||||
|
cis_fingerprint: sm.sm3(params)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (type === 'get') {
|
||||||
|
params = Object.keys(data).map(function (key) {
|
||||||
|
return key + '=' + data[key]
|
||||||
|
}).join('&')
|
||||||
|
} else {
|
||||||
|
params = JSON.stringify(data)
|
||||||
|
}
|
||||||
|
obj = {
|
||||||
|
cis_req_params: sm.sm4.encrypt(params, sm4key),
|
||||||
|
cis_fingerprint: sm.sm3(params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回数据解密
|
||||||
|
* @param data
|
||||||
|
* @param sm4key
|
||||||
|
* @returns {any}
|
||||||
|
*/
|
||||||
|
export function getResponseJson (data, sm4key) {
|
||||||
|
const result = sm.sm4.decrypt(data, sm4key)
|
||||||
|
return JSON.parse(result)
|
||||||
|
}
|
105
web/src/views/Index.vue
Normal file
105
web/src/views/Index.vue
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<template>
|
||||||
|
<div class="index">
|
||||||
|
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="6rem" class="demo-ruleForm">
|
||||||
|
<el-form-item label="请求方式" prop="method">
|
||||||
|
<el-select v-model="ruleForm.method" placeholder="请选择请求方式">
|
||||||
|
<el-option
|
||||||
|
v-for="item in optionsList"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value">
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="姓名" prop="name">
|
||||||
|
<el-input v-model="ruleForm.name" placeholder="请输入姓名"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="座右铭" prop="motto">
|
||||||
|
<el-input v-model="ruleForm.motto" placeholder="请输入座右铭"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import { getRequest, postRequest } from '@/api'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'index',
|
||||||
|
components: {},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
// 表单
|
||||||
|
ruleForm: {
|
||||||
|
// 请求方式
|
||||||
|
method: undefined,
|
||||||
|
// 姓名
|
||||||
|
name: '',
|
||||||
|
// 座右铭
|
||||||
|
motto: ''
|
||||||
|
},
|
||||||
|
// 规则
|
||||||
|
rules: {
|
||||||
|
method: [
|
||||||
|
{ required: true, message: '请选择请求方式', trigger: 'change' }
|
||||||
|
],
|
||||||
|
name: [
|
||||||
|
{ required: true, message: '请输入姓名', trigger: 'blur' },
|
||||||
|
{ min: 3, max: 5, message: '长度在 2 到 5 个字符', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
motto: [
|
||||||
|
{ required: true, message: '请输入座右铭', trigger: 'blur' },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// 请求方式
|
||||||
|
optionsList: [
|
||||||
|
{
|
||||||
|
value: 0,
|
||||||
|
label: 'get'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 1,
|
||||||
|
label: 'post'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* 提交表单
|
||||||
|
*/
|
||||||
|
submitForm (formName) {
|
||||||
|
this.$refs[formName].validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
if (this.ruleForm.method) {
|
||||||
|
postRequest(this.ruleForm).then(res => {
|
||||||
|
console.log(res)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
getRequest(this.ruleForm).then(res => {
|
||||||
|
console.log(res)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('error submit!!')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.index {
|
||||||
|
height: 80vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
</style>
|
65
web/vue.config.js
Normal file
65
web/vue.config.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
module.exports = {
|
||||||
|
// 基本路径
|
||||||
|
publicPath: '/',
|
||||||
|
// 输出文件目录
|
||||||
|
outputDir: 'dist',
|
||||||
|
// eslint-loader 是否在保存的时候检查
|
||||||
|
lintOnSave: false,
|
||||||
|
// use the full build with in-browser compiler?
|
||||||
|
// https://vuejs.org/v2/guide/installation.html#Runtime-Compiler-vs-Runtime-only
|
||||||
|
runtimeCompiler: false,
|
||||||
|
// webpack配置
|
||||||
|
// see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md
|
||||||
|
chainWebpack: () => {},
|
||||||
|
configureWebpack: () => {},
|
||||||
|
// vue-loader 配置项
|
||||||
|
// https://vue-loader.vuejs.org/en/options.html
|
||||||
|
// vueLoader: {},
|
||||||
|
// 生产环境是否生成 sourceMap 文件
|
||||||
|
productionSourceMap: false,
|
||||||
|
// css相关配置
|
||||||
|
/* css: {
|
||||||
|
// 是否使用css分离插件 ExtractTextPlugin
|
||||||
|
extract: true,
|
||||||
|
// 开启 CSS source maps?
|
||||||
|
sourceMap: false,
|
||||||
|
// css预设器配置项
|
||||||
|
loaderOptions: {},
|
||||||
|
// 启用 CSS modules for all css / pre-processor files.
|
||||||
|
modules: false
|
||||||
|
}, */
|
||||||
|
// use thread-loader for babel & TS in production build
|
||||||
|
// enabled by default if the machine has more than 1 cores
|
||||||
|
parallel: require('os').cpus().length > 1,
|
||||||
|
// 是否启用dll
|
||||||
|
// See https://github.com/vuejs/vue-cli/blob/dev/docs/cli-service.md#dll-mode
|
||||||
|
// dll: false,
|
||||||
|
// PWA 插件相关配置
|
||||||
|
// see https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa
|
||||||
|
pwa: {},
|
||||||
|
// webpack-dev-server 相关配置
|
||||||
|
devServer: {
|
||||||
|
// open: process.platform === 'darwin',
|
||||||
|
// 将服务启动后默认打开浏览器
|
||||||
|
open: true,
|
||||||
|
host: '0.0.0.0',
|
||||||
|
port: 8080,
|
||||||
|
https: false,
|
||||||
|
hotOnly: false,
|
||||||
|
proxy: {
|
||||||
|
// detail: https://cli.vuejs.org/config/#devserver-proxy
|
||||||
|
[process.env.VUE_APP_BASE_API]: {
|
||||||
|
target: 'http://localhost:8686',
|
||||||
|
changeOrigin: true,
|
||||||
|
pathRewrite: {
|
||||||
|
['^' + process.env.VUE_APP_BASE_API]: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
before: app => {}
|
||||||
|
},
|
||||||
|
// 第三方插件配置
|
||||||
|
pluginOptions: {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user