1、密钥的获取

package cn.snowpa.common;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Enumeration;@Component
public class MiSecretKey {/*** 加密密钥*/private static String signaturePublic;@Value("${signature.public}")public void setSignaturePublic(String signaturePublic) {MiSecretKey.signaturePublic = signaturePublic;}/*** 加密密钥*/private static String signaturePrivate;@Value("${signature.private}")public void setSignaturePrivate(String signaturePrivate) {MiSecretKey.signaturePrivate = signaturePrivate;}/*** 从文件中获取公钥(公钥的比特编码是X.509格式)** @return* @throws Exception*/public PublicKey getPublicKeyByFile() throws Exception {//建立文件对象File file = new File(signaturePublic);FileInputStream fis = new FileInputStream(file);ByteArrayOutputStream bos = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int len;while ((len = fis.read(buffer)) > 0) {bos.write(buffer, 0, len);}byte[] pbks = Base64.getDecoder().decode(bos.toByteArray());X509EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec(pbks);PublicKey newPbk = KeyFactory.getInstance("RSA").generatePublic(encodedKeySpec);return newPbk;}/*** 从文件中获取公钥(私钥的比特编码是pkcs8格式)** @return* @throws Exception*/public PrivateKey getPrivateKeyByFile() throws Exception {//建立文件对象File file = new File(signaturePrivate);FileInputStream fis = new FileInputStream(file);ByteArrayOutputStream bos = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int len = 0;while ((len = fis.read(buffer)) > 0) {bos.write(buffer, 0, len);}byte[] prks = Base64.getDecoder().decode(bos.toByteArray());/**/PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(prks);PrivateKey newPrk = KeyFactory.getInstance("RSA").generatePrivate(pkcs8EncodedKeySpec);return newPrk;}}

2、生成签名和验证

package cn.snowpa.common;import com.alibaba.fastjson.JSONObject;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;import java.io.IOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;public class MiSignature {/*** 签名算法*/public static final String SIGN_ALGORITHMS = "SHA1WithRSA";/*** 签名算法*/public static final String ENCODE = "utf-8";/*** RSA签名** @param content    待签名数据* @param privateKey 私钥* @return 签名值*/public static String sign(String content, PrivateKey privateKey) {try {Signature signature = Signature.getInstance(SIGN_ALGORITHMS);signature.initSign(privateKey);signature.update(content.getBytes(ENCODE));byte[] signed = signature.sign();return byte2Base64 (signed);} catch (Exception e) {e.printStackTrace();return null;}}/*** 验签** @param content 待签名数据* @param sign    签名值* @param pubKey  公钥* @return 失败时,返回false。*/public static boolean verifySignature (String content, String sign, PublicKey pubKey) {if (null == content || null == sign || "".equals(content) || "".equals(sign)) {return false;}try {byte[] signed = base642Byte(sign);Signature signatureChecker = Signature.getInstance(SIGN_ALGORITHMS);signatureChecker.initVerify(pubKey);signatureChecker.update(content.getBytes());// 验证签名是否正常return signatureChecker.verify(signed);} catch (Exception e) {e.printStackTrace();return false;}}public static String byte2Base64(byte[] bytes) {BASE64Encoder encoder = new BASE64Encoder();return encoder.encode(bytes);}public static byte[] base642Byte(String base64Key) throws IOException {BASE64Decoder decoder = new BASE64Decoder();return decoder.decodeBuffer(base64Key);}// 使json-lib来进行json到map的转换,fastjson有排序问题,不能用public static Map<String, String> jsonToMap (JSONObject json) {Map<String, String> map = new HashMap<>();for (Object key : json.keySet()) {if("sign".equals(key)){continue;}String value = json.getString((String) key);map.put((String) key, value);}Map<String, String> resultMap = sortMapByKey(map);    //按Key进行排序return resultMap;}/*** 使用 Map按key进行排序* @param map* @return*/public static Map<String, String> sortMapByKey(Map<String, String> map) {if (map == null || map.isEmpty()) {return null;}Map<String, String> sortMap = new TreeMap<String, String>(new MapKeyComparator());sortMap.putAll(map);return sortMap;}static class MapKeyComparator implements Comparator<String> {@Overridepublic int compare(String str1, String str2) {return str1.compareTo(str2);}}public static void main(String[] args) {try {// 随机生成一对非对称加密的秘钥对MiSecretKey keyPair = new MiSecretKey();String content = "helloWord123" + ("测试内容");System.out.println("验签内容:" + content);String sign = MiSignature.sign(content, keyPair.getPrivateKeyByFile() );System.out.println("签名结果=" + sign);boolean verify = MiSignature.verifySignature(content, sign, keyPair.getPublicKeyByFile());System.out.println("验签结果="+verify);} catch (Exception e) {e.printStackTrace();}}
}

3、自定义拦截器验证签名


package cn.snowpa.interceptor;import cn.snowpa.common.MiSecretKey;
import cn.snowpa.common.MiSignature;
import cn.snowpa.utils.JsonUtils;
import cn.snowpa.utils.ResultUtil;
import cn.snowpa.utils.StringUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;@Slf4j
public class SystemApiInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {try {JSONObject paramsJson = getRequestParams(request);Map<String,String> content_map = MiSignature.jsonToMap(paramsJson);String sign = paramsJson.getString("sign");log.info("sign:"+sign);String content = content_map.toString();log.info("content:"+content);if (StringUtil.isEmpty(sign))  {write(request, response, JsonUtils.toJson(ResultUtil.error(500,"签名异常")));return false;}MiSecretKey keyPair = new MiSecretKey();boolean verify = MiSignature.verifySignature(content, sign, keyPair.getPublicKeyByFile());log.info("验签结果:"+verify);if(!verify){write(request, response, JsonUtils.toJson(ResultUtil.error(500,"签名异常")));return false;}return true;}catch (Exception e){log.info("异常信息:"+e.getMessage());write(request, response, JsonUtils.toJson(ResultUtil.error(500,"签名异常")));return false;}}// 获取HttpServletRequest里面的参数,并decodeprivate JSONObject getRequestParams(HttpServletRequest request)  throws Exception {ServletInputStream servletInputStream = request.getInputStream();ServletInputStream inputStream = servletInputStream;StringBuilder content = new StringBuilder();byte[] b = new byte[1024];int lens;while ((lens = inputStream.read(b)) > 0) {content.append(new String(b, 0, lens));}String strContent = content.toString(); // 请求体内容log.info("请求体:{}", strContent);JSONObject params = JSON.parseObject(strContent);return params;}/*** 通过response返回错误信息给前端** @param request 请求* @param response 响应* @param content 响应内容*/private void write (HttpServletRequest request, HttpServletResponse response, String content) throws IOException {String origin = request.getHeader("Origin");response.setHeader("Access-Control-Allow-Origin", origin);response.setCharacterEncoding("UTF-8");response.setContentType("application/json; charset=utf-8");response.getWriter().write(content);}
}

4、拦截器的配置-配置拦截URL


package cn.snowpa.interceptor;import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new SystemApiInterceptor()).addPathPatterns("/systemApi/**");}}

5、解决请求体的数据只能获取一次的问题

5.1  请求体数据的处理

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.Charset;public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {private final byte[] body;private String bodyStr;public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {super(request);String bodyString = getBodyString(request);body = bodyString.getBytes(Charset.forName("UTF-8"));bodyStr=bodyString;}public String getBodyStr() {return bodyStr;}@Overridepublic ServletInputStream getInputStream() throws IOException {final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);return new ServletInputStream() {@Overridepublic int read() throws IOException {return byteArrayInputStream.read();}@Overridepublic boolean isFinished() {return false;}@Overridepublic boolean isReady() {return false;}@Overridepublic void setReadListener(ReadListener readListener) {}};}public  String getBodyString(HttpServletRequest request) throws IOException {StringBuilder sb = new StringBuilder();InputStream inputStream = null;BufferedReader reader = null;try {inputStream = request.getInputStream();reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));char[] bodyCharBuffer = new char[1024];int len = 0;while ((len = reader.read(bodyCharBuffer)) != -1) {sb.append(new String(bodyCharBuffer, 0, len));}} catch (IOException e) {e.printStackTrace();} finally {if (inputStream != null) {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}if (reader != null) {try {reader.close();} catch (IOException e) {e.printStackTrace();}}}return sb.toString();}
}

5.2  过滤器调用处理请求体的数据

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;@WebFilter(filterName = "httpServletRequestWrapperFilter", urlPatterns = {"/*"})
public class HttpServletRequestWrapperFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {ServletRequest requestWrapper = null;if (request instanceof HttpServletRequest) {HttpServletRequest httpRequest = (HttpServletRequest) request;//遇到post方法才对request进行包装String methodType = httpRequest.getMethod();if ("POST".equals(methodType)) {requestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) request);}}if (null == requestWrapper) {chain.doFilter(request, response);} else {chain.doFilter(requestWrapper, response);}}@Overridepublic void destroy() {}
}

数字签名 Signature 的使用相关推荐

  1. 数字签名signature是什么?(清晰!)

    作者: 阮一峰 日期: 2011年8月 9日 今天,我读到一篇好文章. 它用图片通俗易懂地解释了,"数字签名"(digital signature)和"数字证书" ...

  2. 简单理解数字签名和验签

    数字签名: "数字签名(又称公钥数字签名.电子签章)是一种类似写在纸上的普通的物理签名,但是使用了公钥加密领域的技术实现,用于鉴别数字信息的方法.一套数字签名通常定义两种互补的运算,一个用于 ...

  3. 用python3实现MD5withRSA数字签名的验证

    在某次安全研究中.需要手工验证下某重要文件MD5withRSA的数字签名是否正确.于是写了个脚本.现记录下来,供大家学习讨论. 1. 数字签名基础知识 数字签名: 一旦选择足够安全的散列算法, 那么就 ...

  4. Java安全之对称加密、非对称加密、数字签名

    Java中加密分为两种方式一个是对称加密,另一个是非对称加密.对称加密是因为加密和解密的钥匙相同,而非对称加密是加密和解密的钥匙不同. 对称加密与非对称加密的区别: 对称加密称为密钥加密,速度快,但加 ...

  5. 数字签名和数字证书使用详解

    目录 1.数字签名 (1)数字签名的应用场景 (2)数字签名的实现原理 (3)如何进行数字签名和验证 (4)使用数字签名的优点和缺点 2.数字证书 (1)如何对数字证书进行颁发和管理 (2)颁发数字证 ...

  6. RSA签名算法,计算调用加密报文,安全传输

    RSA签名算法 1. 获取当前的时间戳参数 2. 计算参数签名 3. 获取请求对象的MD5密文 4. 通过私钥计算某个参数的RSA签名 5. 转换字符集到utf8 6. MD5加密字符串 7. bas ...

  7. [转]Java加密算法

    如基本的单向加密算法: BASE64 严格地说,属于编码格式,而非加密算法 MD5(Message Digest algorithm 5,信息摘要算法) SHA(Secure Hash Algorit ...

  8. java 在线rsa解密_通用的Java RSA加密工具类,可在线验证通过

    /** * RSA加密工具类 * 使用PKCS1_PADDING填充,密钥长度1024 * 加解密结果在这里测试通过:http://tool.chacuo.net/cryptrsaprikey * 注 ...

  9. java-信息安全(十)-数字签名算法DSA

    概述 信息安全基本概念: DSA算法(Digital Signature Algorithm,数据签名算法) DSA Digital Signature Algorithm (DSA)是Schnorr ...

最新文章

  1. nginx反向代理监听非80端口造成的端口丢失解决方案
  2. mysql查询锁表语句和kill对应的线程
  3. 检索数据_5_给字段取个有意义的名字
  4. leetcode 665. 非递减数列(贪心算法)
  5. DotNetBar 教程
  6. Windows操作系统的发展历程
  7. 梦龙即时通讯软件测试初学者,梦龙即时通讯软件
  8. TFN RMT 手持式路测仪 5G NR 手持式频谱分析仪
  9. 基于FileOpen的PDF文档加密
  10. DES的s盒输出CPA和DPA攻击
  11. 简单创意的思维导图怎么画
  12. 思维不要僵化在一种模式
  13. 七大OSINT操作系统(开源网络情报)
  14. 笔记本电脑常识:噪音
  15. ARP渗透与攻防(五)之Ettercap劫持用户流量
  16. 图形编程入门(VS2010)
  17. 青龙面板获取京东ck的新老方法
  18. Spring--BeanUtils工具类--使用/实例
  19. Excel-常用宏技巧(4)
  20. 操作元素总结及作业1——世纪佳缘登录案例-黑马pink老师

热门文章

  1. CSAPP:计算机基本结构与CPU内部构造
  2. Python--元类
  3. ng-zorro table怎么更改滚动条样式
  4. MySQL底层执行原理详解
  5. 36个JavaScript特效教程,学完即精通
  6. OpenGL函数思考-glOrtho
  7. houdini导出粒子到maya的几种方式
  8. 腾讯云验证码入门小知识
  9. Linux命令分享第一天之find命令
  10. Google Earth Engine(GEE)——MODIS/061/MOD09GQ数据缺失波段信息(官方引入数据超时)