zuul网关RSA签名,AES加密

请求request处理

代码只支持get,post
链接https://blog.csdn.net/whatzhang007/article/details/122451527

@Slf4j
@Component
public class RequestParamsFilter extends ZuulFilter {

    public static final String T_KEY = "t";
    public static final String S_KEY = "s";
    @Value("${spider-encrypt.privateKey}")
    private String privateKey;

    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return 13;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        RequestContext ctx = getCurrentContext();
        //默认不加密
        ctx.set("isEncrypt", false);
        HttpServletRequest request = ctx.getRequest();
        String method = request.getMethod();
        String timestamp = request.getHeader("X-TIMESTAMP");
        String cipher = request.getHeader("X-CIPHER");
        if (StringUtils.isEmpty(timestamp) && StringUtils.isEmpty(cipher)) {
            ctx.set("isEncrypt", false);
            return true;
        }
        ctx.set("isEncrypt", true);
        if (StringUtils.isEmpty(timestamp) || StringUtils.isEmpty(cipher)) {
            ReturnUtil.writeErrorMsg(RespCode.HEADER_MISS, HttpStatus.UNAUTHORIZED);
            return false;
        }

        //解密
        String str = EncryptUtil.rsaPrivateDecrypt(privateKey, cipher);
        //k=abH2Dwerfd45dw3e:1641440872952
        Map<String, Object> map = mapParameter(getDecryptData(str));
        if (CollectionUtils.isEmpty(map)) {
            log.warn("解析加密请求头内容为空");
            ReturnUtil.writeErrorMsg(RespCode.TEST_REQUEST_ERROR, HttpStatus.UNAUTHORIZED);
            return false;
        }
        //判断时间戳
        String stamp = (String) map.get(T_KEY);
        String salt = (String) map.get(S_KEY);
        long now = System.currentTimeMillis();
        long max = now + 60 * 1000;
        long min = now - 60 * 1000;
        long tt = Long.parseLong(StringUtils.isEmpty(stamp) ? "0" : stamp);
        if (StringUtils.isEmpty(salt) || StringUtils.isEmpty(stamp) || !Objects.equals(timestamp, stamp) || (tt > max || tt < min)) {
            log.warn("验签失败, 解码后的参数为{}", map);
            ReturnUtil.writeErrorMsg(RespCode.ILLEGAL_PARAM, HttpStatus.UNAUTHORIZED);
            return false;
        }

        if (HttpMethod.POST.name().equalsIgnoreCase(method)) {
            //application/json参数
            try (InputStream in = ctx.getRequest().getInputStream()) {
                String requestBody = StreamUtils.copyToString(in, StandardCharsets.UTF_8);
                requestBody = EncryptUtil.aesDecrypt(requestBody, salt);

                byte[] bytes = StringUtils.isEmpty(requestBody) ? new byte[0] : requestBody.getBytes(StandardCharsets.UTF_8);
                ctx.setRequest(new HttpServletRequestWrapper(ctx.getRequest()) {
                    @Override
                    public ServletInputStream getInputStream() {
                        return new ServletInputStreamWrapper(bytes);
                    }

                    @Override
                    public int getContentLength() {
                        return bytes.length;
                    }

                    @Override
                    public long getContentLengthLong() {
                        return bytes.length;
                    }

                    @Override
                    public String getContentType() {
                        return MediaType.APPLICATION_JSON_UTF8.toString();
                    }

                });
            } catch (Exception e) {
                log.error("[请求参数] 解析requestBody失败", e);
            }
        }
        return null;
    }

    public Map<String, List<String>> getDecryptData(String str) {
        if (org.apache.commons.lang.StringUtils.isBlank(str)) {
            return new HashMap<>(0);
        }
        HashMap<String, List<String>> map = Maps.newHashMap();
        StringTokenizer st = new StringTokenizer(str, "&");
        int i;
        while (st.hasMoreTokens()) {
            String s = st.nextToken();
            i = s.indexOf("=");
            getTokenParams(map, i, s);
        }
        return map;
    }

    private void getTokenParams(HashMap<String, List<String>> map, int i, String s) {
        if (i > 0 && s.length() >= i + 1) {
            String name = s.substring(0, i);
            String value = s.substring(i + 1);
            List<String> valueList = map.get(name);
            if (Objects.isNull(valueList)) {
                valueList = new LinkedList<>();
                map.put(name, valueList);
            }
            valueList.add(value);
        } else if (i == -1) {
            String name = s;
            String value = "";
            try {
                name = URLDecoder.decode(name, StandardCharsets.UTF_8.name());
            } catch (Exception e) {
                log.warn("[请求参数] decode name=[{}] error", name);
            }
            List<String> valueList = map.get(name);
            if (Objects.isNull(valueList)) {
                valueList = new LinkedList<>();
                map.put(name, valueList);
            }
            valueList.add(value);
        }
    }

    private Map<String, Object> mapParameter(Map<String, List<String>> map) {
        if (CollectionUtils.isEmpty(map)) {
            return new HashMap<>(0);
        }
        Map<String, Object> rtn = Maps.newHashMap();
        map.forEach((k, v) -> {
            if (!CollectionUtils.isEmpty(v)) {
                if (v.size() == 1) {
                    rtn.put(k, v.get(0));
                } else {
                    rtn.put(k, v);
                }
            } else {
                rtn.put(k, v);
            }
        });
        return rtn;
    }
}

请求response处理

@Slf4j
@Component
public class ResponseParamsFilter extends ZuulFilter {
    @Value("${spider-encrypt.privateKey}")
    private String privateKey;

    @Override
    public String filterType() {
        return FilterConstants.POST_TYPE;
    }

    @Override
    public int filterOrder() {
        return 800;
    }

    @Override
    public boolean shouldFilter() {
        Boolean isEncrypt = (Boolean) RequestContext.getCurrentContext().get("isEncrypt");
        Boolean errorReturn = (Boolean) RequestContext.getCurrentContext().get("error_return");
        boolean encrypt = Objects.isNull(isEncrypt) ? false : isEncrypt;
        boolean error = Objects.isNull(errorReturn) ? false : errorReturn;
        //异常返回不加密
        return encrypt && !error;
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletResponse response = ctx.getResponse();
        String respBody = ctx.getResponseBody();
        if (StringUtils.isBlank(respBody)) {
            try (InputStream stream = RequestContext.getCurrentContext().getResponseDataStream()) {
                respBody = IOUtils.toString(stream, StandardCharsets.UTF_8);
            } catch (Exception e) {
                log.error("[获取响应体数据]异常", e);
                ReturnUtil.writeErrorMsg(RespCode.GET_RESP_BODY_ERROR, HttpStatus.INTERNAL_SERVER_ERROR);
                return false;
            }
        }
        if (StringUtils.isEmpty(respBody)) {
            log.info("[获取响应体数据]responseBody为空");
            return false;
        }
        //加密
        String salt = EncryptUtil.getRandomString(16);
        String timestamp = String.valueOf(System.currentTimeMillis());
        //加密
        respBody = EncryptUtil.aesEncrypt(respBody, salt);
        RequestContext.getCurrentContext().setResponseBody(respBody);
        response.setContentLength(respBody.length());
        response.setHeader("X-TIMESTAMP", timestamp);
        response.setHeader("X-CIPHER", EncryptUtil.rsaPrivateEncrypt(privateKey,
                RequestParamsFilter.S_KEY + "=" + salt + "&" + RequestParamsFilter.T_KEY + "=" + timestamp));
        return true;
    }
}

工具类

public class ReturnUtil {
    private static final String KEY_CODE = "CODE";
    private static final String KEY_MSG = "MSG";

    private ReturnUtil() {
        throw new IllegalStateException("Utility class");
    }

    public static void writeErrorMsg(RespCode error, HttpStatus statusCode) {
        RequestContext ctx = getCurrentContext();
        ctx.setSendZuulResponse(false);
        ctx.set("error_return", true);
        ctx.setResponseStatusCode(statusCode.value());
        HttpServletResponse response = ctx.getResponse();
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");
        Map<String, Object> map = new HashMap<>(2);
        map.put(KEY_CODE, error.getCode());
        map.put(KEY_MSG, error.getMsg());
        ctx.setResponseBody(JSONUtil.toJsonStr(map));
    }
}
@Slf4j
public class EncryptUtil {

    public static final String RSA = "RSA";
    public static final String RSA_ECB_NO_PADDING = "RSA/ECB/PKCS1Padding";
    public static final String AES_ECB_PKCS_5_PADDING = "AES/ECB/PKCS5Padding";
    public static final String AES = "AES";

    private EncryptUtil() {
        throw new IllegalStateException("Utility class");
    }

    public static String rsaPublicEncrypt(String publicKey, String data) {
        if (StringUtils.isBlank(data)) {
            return "";
        }
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(RSA);
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
            RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
            Cipher cipher = Cipher.getInstance(RSA_ECB_NO_PADDING);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] bytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
            return Base64.encodeBase64String(bytes);
        } catch (Exception e) {
            log.error("rsaPublicEncrypt error", e);
        }
        return null;
    }

    public static String rsaPublicDecrypt(String publicKey, String data) {
        if (StringUtils.isBlank(data)) {
            return "";
        }
        try {
            byte[] dataBytes = Base64.decodeBase64(data);
            KeyFactory keyFactory = KeyFactory.getInstance(RSA);
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
            RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
            Cipher cipher = Cipher.getInstance(RSA_ECB_NO_PADDING);
            cipher.init(Cipher.DECRYPT_MODE, key);
            return new String(cipher.doFinal(dataBytes));
        } catch (Exception e) {
            log.error("rsaPublicDecrypt error", e);
        }
        return null;
    }

    public static String rsaPrivateEncrypt(String privateKey, String data) {
        if (StringUtils.isBlank(data)) {
            return "";
        }
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(RSA);
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
            RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
            Cipher cipher = Cipher.getInstance(RSA_ECB_NO_PADDING);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] bytes = cipher.doFinal(data.getBytes());
            return Base64.encodeBase64String(bytes);
        } catch (Exception e) {
            log.error("rsaPrivateEncrypt error", e);
        }
        return null;
    }

    public static String rsaPrivateDecrypt(String privateKey, String data) {
        if (StringUtils.isBlank(data)) {
            return "";
        }
        try {
            byte[] dataBytes = Base64.decodeBase64(data);
            KeyFactory keyFactory = KeyFactory.getInstance(RSA);
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
            RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
            Cipher cipher = Cipher.getInstance(RSA_ECB_NO_PADDING);
            cipher.init(Cipher.DECRYPT_MODE, key);
            return new String(cipher.doFinal(dataBytes));
        } catch (Exception e) {
            log.error("rsaPrivateDecrypt error", e);
        }
        return null;
    }

    public static String aesEncrypt(String data, String key) {
        if (StringUtils.isBlank(data)) {
            return "";
        }
        try {
            Cipher cipher = Cipher.getInstance(AES_ECB_PKCS_5_PADDING);
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes(), AES));
            return Base64.encodeBase64String(cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)));
        } catch (Exception e) {
            log.error("aesDecryptData error", e);
        }
        return "";
    }

    public static String aesDecrypt(String data, String key) {
        if (StringUtils.isBlank(data)) {
            return "";
        }
        try {
            Cipher cipher = Cipher.getInstance(AES_ECB_PKCS_5_PADDING);
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes(), AES));
            return new String(cipher.doFinal(Base64.decodeBase64(data)));
        } catch (Exception e) {
            log.error("aesDecryptData error", e);
        }
        return "";
    }

    public static String getRandomString(int length) {
        String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random = new Random();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; ++i) {
            int number = random.nextInt(62);
            sb.append(str.charAt(number));
        }
        return sb.toString();
    }
}
@Getter
@AllArgsConstructor
public enum RespCode {

    SUCCESS("000000", "SUCCESS"),
    SYSTEM_ERROR("B00001", "系统异常"),
    HEADER_MISS("A05002", "缺少关键header"),
    ILLEGAL_PARAM("A05003", "未经授权的请求"),
    GET_RESP_BODY_ERROR("A05004", "解析结果异常"),
    TEST_REQUEST_ERROR("A05005", "验签异常"),
    ;
    private final String code;

    private final String msg;
}
上一篇:函数4传递任意数量的参数-python进阶篇四


下一篇:Python warning警告出现的原因及忽略方法