SpringBootでのブロッキングの運用(特定のリクエストのタイムスタンプとRSA署名を検証)


SpringBootでブロッキングを実装するには、WebMvcConfigurerAdapterクラスを継承する必要があります.このクラスでは、webMvcConfigインタフェースの抽象クラスが実装され、次に、このクラスの対応する抽象メソッドを実装することができます.
    @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つ目は、ブロッカーにブロッカーを要求することです.そうすれば、具体的なビジネスロジックを実現するだけでいいです.
  • 独自のブロッキングクラスを作成し、HandlerInterceptorインタフェース
  • を実装する.
    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つのステップを完了する必要があります.
  • 独自のブロッキングクラスを作成し、HandlerInterceptorインタフェース
  • を実装する.
  • WebMvcConfigurerAdapterクラスのaddInterceptorsメソッドを書き換えるカスタムブロッキングクラスを追加すれば
  • です.
    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; } }

    今回はブログを書いて記録して、蓄積しても共有してもいいです.