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;
}
标签:网关,return,String,AES,RSA,cipher,error,new,public 来源: https://blog.csdn.net/whatzhang007/article/details/122451903