SpringBootでのブロッキングの運用(特定のリクエストのタイムスタンプとRSA署名を検証)
12989 ワード
SpringBootでブロッキングを実装するには、WebMvcConfigurerAdapterクラスを継承する必要があります.このクラスでは、webMvcConfigインタフェースの抽象クラスが実装され、次に、このクラスの対応する抽象メソッドを実装することができます.
上記のコードは2つのことをしました.1つ目は、beanコンテナにカスタムブロッカーを注入して管理することです.2つ目は、ブロッカーにブロッカーを要求することです.そうすれば、具体的なビジネスロジックを実現するだけでいいです.独自のブロッキングクラスを作成し、HandlerInterceptorインタフェース を実装する.
多くの共通のコードが抽象化されているため、送信されたパラメータをソートした後、自身のRSA公開鍵を利用して復号化チェックを行い、タイムスタンプに対して1分間の有効性チェックを行い、チェックに成功すればtrueに戻って次のコードを実行し続け、そうでなければfalseに戻って断言を実行する.
簡単に言えば、ブロッキング機能を実現するには、2つのステップを完了する必要があります.独自のブロッキングクラスを作成し、HandlerInterceptorインタフェース を実装する. WebMvcConfigurerAdapterクラスのaddInterceptorsメソッドを書き換えるカスタムブロッキングクラスを追加すれば です.
RSA復号化のルールについては、次のコードを参照してください(RSA復号化に関する別のブログでは、RSA証明書復号化を参照してください).
今回はブログを書いて記録して、蓄積しても共有してもいいです.
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(paramsValidInterceptor())
.addPathPatterns("/terminalCall/syncMachine")
.addPathPatterns("/terminalCall/channelGoodsList");
}
/**
*
* @return
*/
@Bean
public ParamsValidInterceptor paramsValidInterceptor(){
return new ParamsValidInterceptor();
}
上記のコードは2つのことをしました.1つ目は、beanコンテナにカスタムブロッカーを注入して管理することです.2つ目は、ブロッカーにブロッカーを要求することです.そうすれば、具体的なビジネスロジックを実現するだけでいいです.
package com.youfuli.vendor.interceptor;
import com.youfuli.vendor.constant.Messages;
import com.youfuli.vendor.utils.RSA2;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.ResourceUtils;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.apache.commons.codec.binary.Base64;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;
/**
* Created by on 2019/3/13.
*/
@Slf4j
@Component
public class ParamsValidInterceptor extends HandlerInterceptorAdapter {
@Value("${rsa.pubKey}")
String pubKey;
@Value("${rsa.priKey}")
String priKey;
@Value("${rsa.pwd}")
String pwd;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String times = (System.currentTimeMillis()/1000)+"";
log.info(" {}",times);
log.info(" {}",request.getRequestURL());
Map maps = request.getParameterMap();
//
Assert.isTrue(checkTimeStamp(new Long(maps.get("timeStamp")[0])), Messages.TIMESPAN_INVALID);
//
String signStr = maps.get("sign")[0];
log.info(" {}",signStr);
//
String returnString = key_sort(maps);
log.info(" {}",returnString);
//
File pubfile = ResourceUtils.getFile(pubKey);
String publicKey = txt2String(pubfile).replaceAll("(\\\r\\
|\\\r|\\
|\\
\\\r)", "");
//
File prifile = ResourceUtils.getFile(priKey);
String privateKey = txt2String(prifile).replaceAll("(\\\r\\
|\\\r|\\
|\\
\\\r)", "");
// ---
byte [] signValidStr = RSA2.sign(returnString.getBytes(),privateKey);
String signValid = Base64.encodeBase64String(signValidStr);
boolean verfiy;
if(signValid.equals(signStr)){
verfiy = RSA2.verify(returnString.getBytes(),signValidStr,publicKey);
log.info(" {}",verfiy);
}else{
verfiy=false;
}
if(verfiy==false){
Assert.isTrue(verfiy,Messages.VALID_SIGN_ERROR);
}
return verfiy;
}
/**
*
**/
public static String key_sort(Map map) {
String key_sort = "";
TreeMap map2 = new TreeMap(new Comparator() {
public int compare(String obj1, String obj2) {
//
return obj2.compareTo(obj1);
}
});
map2 = new TreeMap<>(map);
map2.remove("sign");
Set keySet = map2.keySet();
Iterator iter = keySet.iterator();
while (iter.hasNext()) {
String key = iter.next();
key_sort = key_sort + key + "=" + map2.get(key)[0] + "&";
}
return key_sort.substring(0, key_sort.length() - 1);
}
/**
*
**/
private static boolean checkTimeStamp(long ts)
{
if (Math.abs(ts - System.currentTimeMillis() / 1000) > 60)
{
return false;
}
return true;
}
/**
* String
**/
public static String txt2String(File file){
StringBuilder result = new StringBuilder();
try{
BufferedReader br = new BufferedReader(new FileReader(file));// BufferedReader
String s = null;
while((s = br.readLine())!=null){// readLine ,
result.append(System.lineSeparator()+s);
}
br.close();
}catch(Exception e){
e.printStackTrace();
}
return result.toString();
}
}
多くの共通のコードが抽象化されているため、送信されたパラメータをソートした後、自身のRSA公開鍵を利用して復号化チェックを行い、タイムスタンプに対して1分間の有効性チェックを行い、チェックに成功すればtrueに戻って次のコードを実行し続け、そうでなければfalseに戻って断言を実行する.
簡単に言えば、ブロッキング機能を実現するには、2つのステップを完了する必要があります.
RSA復号化のルールについては、次のコードを参照してください(RSA復号化に関する別のブログでは、RSA証明書復号化を参照してください).
package com.youfuli.vendor.utils;
import org.apache.commons.codec.binary.Base64;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
/**
* Created by on 2019/3/13.
*/
public class RSA2 {
public static final String KEY_ALGORITHM = "RSA";
private static final String PUBLIC_KEY = "RSAPublicKey";
private static final String PRIVATE_KEY = "RSAPrivateKey";
public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
/**
* RSA
*/
private static final int MAX_ENCRYPT_BLOCK = 117;
/**
* RSA
*/
private static final int MAX_DECRYPT_BLOCK = 2048;
//
public static String getPublicKeyStr(Map keyMap) throws Exception {
// map key
Key key = (Key) keyMap.get(PUBLIC_KEY);
//
return encryptBASE64(key.getEncoded());
}
//
public static String getPrivateKeyStr(Map keyMap) throws Exception {
// map key
Key key = (Key) keyMap.get(PRIVATE_KEY);
//
return encryptBASE64(key.getEncoded());
}
//
public static PublicKey getPublicKey(String key) throws Exception {
byte[] keyBytes;
keyBytes = (new BASE64Decoder()).decodeBuffer(key);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PublicKey publicKey = keyFactory.generatePublic(keySpec);
return publicKey;
}
//
public static PrivateKey getPrivateKey(String key) throws Exception {
byte[] keyBytes;
keyBytes = (new BASE64Decoder()).decodeBuffer(key);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
return privateKey;
}
// byte
public static byte[] decryptBASE64(String key) throws Exception {
return (new BASE64Decoder()).decodeBuffer(key);
}
//
public static String encryptBASE64(byte[] key) throws Exception {
return (new BASE64Encoder()).encodeBuffer(key);
}
//*************************** *******************************
public static byte[] sign(byte[] data, String privateKeyStr) throws Exception {
PrivateKey priK = getPrivateKey(privateKeyStr);
Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM);
sig.initSign(priK);
sig.update(data);
return sig.sign();
}
public static boolean verify(byte[] data, byte[] sign, String publicKeyStr) throws Exception {
PublicKey pubK = getPublicKey(publicKeyStr);
Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM);
sig.initVerify(pubK);
sig.update(data);
return sig.verify(sign);
}
//************************ **************************
public static byte[] encrypt(byte[] plainText, String publicKeyStr) throws Exception {
PublicKey publicKey = getPublicKey(publicKeyStr);
Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
int inputLen = plainText.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
int i = 0;
byte[] cache;
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
cache = cipher.doFinal(plainText, offSet, MAX_ENCRYPT_BLOCK);
} else {
cache = cipher.doFinal(plainText, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptText = out.toByteArray();
out.close();
return encryptText;
}
public static byte[] decrypt(byte[] encryptText, String privateKeyStr) throws Exception {
PrivateKey privateKey = getPrivateKey(privateKeyStr);
Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
int inputLen = encryptText.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
//
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
cache = cipher.doFinal(encryptText, offSet, MAX_DECRYPT_BLOCK);
} else {
cache = cipher.doFinal(encryptText, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_DECRYPT_BLOCK;
}
byte[] plainText = out.toByteArray();
out.close();
return plainText;
}
public static void main(String[] args) {
Map keyMap;
byte[] cipherText;
String input = "Hello World!";
try {
keyMap = initKey();
String publicKey = getPublicKeyStr(keyMap);
System.out.println(" ------------------");
System.out.println(publicKey);
String privateKey = getPrivateKeyStr(keyMap);
System.out.println(" ------------------");
System.out.println(privateKey);
System.out.println(" -------------------");
System.out.println(" =======" + input);
cipherText = encrypt(input.getBytes(), publicKey);
//
System.out.println(" =======" + new String(cipherText));
//
byte[] plainText = decrypt(cipherText, privateKey);
System.out.println(" ===== " + new String(plainText));
System.out.println(" -----------");
String str = "431f4dfd4c862122fb8a4e004c9a093b";
System.out.println("
:" + str);
byte[] signature = sign(str.getBytes(), privateKey);
System.out.println(Base64.encodeBase64String(signature));
boolean status = verify(str.getBytes(), signature, publicKey);
System.out.println(" :" + status);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Map initKey() throws Exception {
KeyPairGenerator keyPairGen = KeyPairGenerator
.getInstance(KEY_ALGORITHM);
keyPairGen.initialize(1024);
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
Map keyMap = new HashMap(2);
keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
}
}
今回はブログを書いて記録して、蓄積しても共有してもいいです.