ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

zuul网关RSA签名,AES加密

2022-01-12 14:00:44  阅读:198  来源: 互联网

标签:网关 return String AES RSA cipher error new public


请求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;
}

标签:网关,return,String,AES,RSA,cipher,error,new,public
来源: https://blog.csdn.net/whatzhang007/article/details/122451903

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有