Dedicated line crypto
This commit is contained in:
@@ -27,6 +27,7 @@ import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Mono;
|
||||
import we.dedicated_line.DedicatedLineService;
|
||||
import we.flume.clients.log4j2appender.LogService;
|
||||
import we.plugin.FizzPluginFilter;
|
||||
import we.plugin.FizzPluginFilterChain;
|
||||
import we.util.ReactorUtils;
|
||||
@@ -76,7 +77,7 @@ public class DedicatedLineApiAuthPluginFilter implements FizzPluginFilter {
|
||||
return WebUtils.response(exchange, HttpStatus.UNAUTHORIZED, null, respJson);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("{} {} exception", traceId, DEDICATED_LINE_API_AUTH_PLUGIN_FILTER, e);
|
||||
log.error("{} {} exception", traceId, DEDICATED_LINE_API_AUTH_PLUGIN_FILTER, LogService.BIZ_ID, traceId, e);
|
||||
String respJson = WebUtils.jsonRespBody(HttpStatus.INTERNAL_SERVER_ERROR.value(),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase(), traceId);
|
||||
return WebUtils.response(exchange, HttpStatus.INTERNAL_SERVER_ERROR, null, respJson);
|
||||
|
||||
@@ -17,11 +17,9 @@
|
||||
|
||||
package we.plugin.dedicatedline.codec;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
|
||||
import cn.hutool.crypto.symmetric.SymmetricCrypto;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.slf4j.Logger;
|
||||
@@ -35,97 +33,123 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
|
||||
import cn.hutool.crypto.symmetric.SymmetricCrypto;
|
||||
import reactor.core.publisher.Mono;
|
||||
import we.config.SystemConfig;
|
||||
import we.dedicated_line.DedicatedLineService;
|
||||
import we.flume.clients.log4j2appender.LogService;
|
||||
import we.plugin.FizzPluginFilterChain;
|
||||
import we.plugin.auth.App;
|
||||
import we.plugin.auth.AppService;
|
||||
import we.plugin.requestbody.RequestBodyPlugin;
|
||||
import we.spring.http.server.reactive.ext.FizzServerHttpRequestDecorator;
|
||||
import we.spring.http.server.reactive.ext.FizzServerHttpResponseDecorator;
|
||||
import we.util.Consts;
|
||||
import we.util.NettyDataBufferUtils;
|
||||
import we.util.WebUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Francis Dong
|
||||
*
|
||||
*/
|
||||
@ConditionalOnBean(DedicatedLineService.class)
|
||||
@Component(DedicatedLineCodecPluginFilter.DEDICATED_LINE_CODEC_PLUGIN_FILTER)
|
||||
public class DedicatedLineCodecPluginFilter extends RequestBodyPlugin {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(DedicatedLineCodecPluginFilter.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(DedicatedLineCodecPluginFilter.class);
|
||||
|
||||
public static final String DEDICATED_LINE_CODEC_PLUGIN_FILTER = "dedicatedLineCodecPlugin";
|
||||
public static final String DEDICATED_LINE_CODEC_PLUGIN_FILTER = "dedicatedLineCodecPlugin";
|
||||
|
||||
@Resource
|
||||
private SystemConfig systemConfig;
|
||||
@Resource
|
||||
private SystemConfig systemConfig;
|
||||
|
||||
@Resource
|
||||
private DedicatedLineService dedicatedLineService;
|
||||
@Resource
|
||||
private DedicatedLineService dedicatedLineService;
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Override
|
||||
public Mono<Void> doFilter(ServerWebExchange exchange, Map<String, Object> config) {
|
||||
String traceId = WebUtils.getTraceId(exchange);
|
||||
try {
|
||||
LogService.setBizId(traceId);
|
||||
String dedicatedLineId = WebUtils.getDedicatedLineId(exchange);
|
||||
String secretKey = dedicatedLineService.getPairCodeSecretKey(dedicatedLineId);
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
@Override
|
||||
public Mono<Void> doFilter(ServerWebExchange exchange, Map<String, Object> config) {
|
||||
String traceId = WebUtils.getTraceId(exchange);
|
||||
try {
|
||||
LogService.setBizId(traceId);
|
||||
String dedicatedLineId = WebUtils.getDedicatedLineId(exchange);
|
||||
// String secretKey = dedicatedLineService.getPairCodeSecretKey(dedicatedLineId);
|
||||
|
||||
FizzServerHttpRequestDecorator request = (FizzServerHttpRequestDecorator) exchange.getRequest();
|
||||
return request.getBody().defaultIfEmpty(NettyDataBufferUtils.EMPTY_DATA_BUFFER).single().flatMap(body -> {
|
||||
String reqBody = body.toString(StandardCharsets.UTF_8);
|
||||
request.setBody(decrypt(reqBody, secretKey));
|
||||
FizzServerHttpRequestDecorator request = (FizzServerHttpRequestDecorator) exchange.getRequest();
|
||||
return request.getBody().defaultIfEmpty(NettyDataBufferUtils.EMPTY_DATA_BUFFER).single().flatMap(body -> {
|
||||
/*String reqBody = body.toString(StandardCharsets.UTF_8);
|
||||
request.setBody(decrypt(reqBody, secretKey));*/
|
||||
|
||||
ServerHttpResponse original = exchange.getResponse();
|
||||
FizzServerHttpResponseDecorator fizzServerHttpResponseDecorator = new FizzServerHttpResponseDecorator(
|
||||
original) {
|
||||
@Override
|
||||
public Publisher<? extends DataBuffer> writeWith(DataBuffer remoteResponseBody) {
|
||||
String respBody = remoteResponseBody.toString(StandardCharsets.UTF_8);
|
||||
HttpHeaders headers = getDelegate().getHeaders();
|
||||
headers.setContentType(MediaType.TEXT_PLAIN);
|
||||
headers.remove(HttpHeaders.CONTENT_LENGTH);
|
||||
NettyDataBuffer from = NettyDataBufferUtils.from(encrypt(respBody, secretKey));
|
||||
return Mono.just(from);
|
||||
}
|
||||
};
|
||||
ServerWebExchange build = exchange.mutate().response(fizzServerHttpResponseDecorator).build();
|
||||
return FizzPluginFilterChain.next(build);
|
||||
});
|
||||
String cryptoKey = systemConfig.fizzDedicatedLineClientRequestSecretkey();
|
||||
if (body != NettyDataBufferUtils.EMPTY_DATA_BUFFER && StringUtils.isNotBlank(cryptoKey)) {
|
||||
byte[] bodyBytes = request.getBodyBytes();
|
||||
request.setBody(decrypt(bodyBytes, cryptoKey));
|
||||
request.getHeaders().remove(HttpHeaders.CONTENT_LENGTH);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("{} {} Exception", traceId, DEDICATED_LINE_CODEC_PLUGIN_FILTER, e, LogService.BIZ_ID, traceId);
|
||||
String respJson = WebUtils.jsonRespBody(HttpStatus.INTERNAL_SERVER_ERROR.value(),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase(), traceId);
|
||||
return WebUtils.response(exchange, HttpStatus.INTERNAL_SERVER_ERROR, null, respJson);
|
||||
}
|
||||
}
|
||||
ServerHttpResponse original = exchange.getResponse();
|
||||
FizzServerHttpResponseDecorator fizzServerHttpResponseDecorator = new FizzServerHttpResponseDecorator(original) {
|
||||
@Override
|
||||
public Publisher<? extends DataBuffer> writeWith(DataBuffer remoteResponseBody) {
|
||||
/*String respBody = remoteResponseBody.toString(StandardCharsets.UTF_8);
|
||||
HttpHeaders headers = getDelegate().getHeaders();
|
||||
headers.setContentType(MediaType.TEXT_PLAIN);
|
||||
headers.remove(HttpHeaders.CONTENT_LENGTH);
|
||||
NettyDataBuffer from = NettyDataBufferUtils.from(encrypt(respBody, secretKey));
|
||||
return Mono.just(from);*/
|
||||
if (remoteResponseBody == NettyDataBufferUtils.EMPTY_DATA_BUFFER) {
|
||||
return Mono.empty();
|
||||
} else {
|
||||
if (StringUtils.isNotBlank(cryptoKey)) {
|
||||
getDelegate().getHeaders().remove(HttpHeaders.CONTENT_LENGTH);
|
||||
byte[] bytes = remoteResponseBody.asByteBuffer().array();
|
||||
NettyDataBuffer from = NettyDataBufferUtils.from(encrypt(bytes, cryptoKey));
|
||||
return Mono.just(from);
|
||||
} else {
|
||||
return Mono.just(remoteResponseBody);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
ServerWebExchange build = exchange.mutate().response(fizzServerHttpResponseDecorator).build();
|
||||
return FizzPluginFilterChain.next(build);
|
||||
});
|
||||
|
||||
public String encrypt(String data, String secretKey) {
|
||||
if (StringUtils.isBlank(data)) {
|
||||
return data;
|
||||
}
|
||||
byte[] key = SecureUtil.decode(secretKey);
|
||||
SymmetricCrypto symmetric = new SymmetricCrypto(SymmetricAlgorithm.AES, key);
|
||||
return symmetric.encryptBase64(data);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("{} {} Exception", traceId, DEDICATED_LINE_CODEC_PLUGIN_FILTER, LogService.BIZ_ID, traceId, e);
|
||||
String respJson = WebUtils.jsonRespBody(HttpStatus.INTERNAL_SERVER_ERROR.value(),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase(), traceId);
|
||||
return WebUtils.response(exchange, HttpStatus.INTERNAL_SERVER_ERROR, null, respJson);
|
||||
}
|
||||
}
|
||||
|
||||
public String decrypt(String data, String secretKey) {
|
||||
if (StringUtils.isBlank(data)) {
|
||||
return data;
|
||||
}
|
||||
byte[] key = SecureUtil.decode(secretKey);
|
||||
SymmetricCrypto symmetric = new SymmetricCrypto(SymmetricAlgorithm.AES, key);
|
||||
return symmetric.decryptStr(data);
|
||||
}
|
||||
public String encrypt(String data, String secretKey) {
|
||||
if (StringUtils.isBlank(data)) {
|
||||
return data;
|
||||
}
|
||||
byte[] key = SecureUtil.decode(secretKey);
|
||||
SymmetricCrypto symmetric = new SymmetricCrypto(SymmetricAlgorithm.AES, key);
|
||||
return symmetric.encryptBase64(data);
|
||||
}
|
||||
|
||||
public byte[] encrypt(byte[] data, String secretKey) {
|
||||
byte[] key = SecureUtil.decode(secretKey);
|
||||
SymmetricCrypto symmetric = new SymmetricCrypto(SymmetricAlgorithm.AES, key);
|
||||
return symmetric.encrypt(data);
|
||||
}
|
||||
|
||||
public String decrypt(String data, String secretKey) {
|
||||
if (StringUtils.isBlank(data)) {
|
||||
return data;
|
||||
}
|
||||
byte[] key = SecureUtil.decode(secretKey);
|
||||
SymmetricCrypto symmetric = new SymmetricCrypto(SymmetricAlgorithm.AES, key);
|
||||
return symmetric.decryptStr(data);
|
||||
}
|
||||
|
||||
public byte[] decrypt(byte[] data, String secretKey) {
|
||||
byte[] key = SecureUtil.decode(secretKey);
|
||||
SymmetricCrypto symmetric = new SymmetricCrypto(SymmetricAlgorithm.AES, key);
|
||||
return symmetric.decrypt(data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,10 +17,6 @@
|
||||
|
||||
package we.plugin.dedicatedline.pairing;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -29,105 +25,101 @@ import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
import we.config.SystemConfig;
|
||||
import we.dedicated_line.DedicatedLineService;
|
||||
import we.flume.clients.log4j2appender.LogService;
|
||||
import we.plugin.FizzPluginFilter;
|
||||
import we.plugin.FizzPluginFilterChain;
|
||||
import we.plugin.auth.App;
|
||||
import we.plugin.auth.AppService;
|
||||
import we.util.DigestUtils;
|
||||
import we.util.ReactorUtils;
|
||||
import we.util.WebUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Francis Dong
|
||||
*
|
||||
*/
|
||||
@ConditionalOnBean(DedicatedLineService.class)
|
||||
@Component(DedicatedLinePairingPluginFilter.DEDICATED_LINE_PAIRING_PLUGIN_FILTER)
|
||||
public class DedicatedLinePairingPluginFilter implements FizzPluginFilter {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(DedicatedLinePairingPluginFilter.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(DedicatedLinePairingPluginFilter.class);
|
||||
|
||||
public static final String DEDICATED_LINE_PAIRING_PLUGIN_FILTER = "dedicatedLinePairingPlugin";
|
||||
public static final String DEDICATED_LINE_PAIRING_PLUGIN_FILTER = "dedicatedLinePairingPlugin";
|
||||
|
||||
@Resource
|
||||
private SystemConfig systemConfig;
|
||||
@Resource
|
||||
private SystemConfig systemConfig;
|
||||
|
||||
@Resource
|
||||
private DedicatedLineService dedicatedLineService;
|
||||
@Resource
|
||||
private DedicatedLineService dedicatedLineService;
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, Map<String, Object> config) {
|
||||
String traceId = WebUtils.getTraceId(exchange);
|
||||
try {
|
||||
LogService.setBizId(traceId);
|
||||
String dedicatedLineId = WebUtils.getDedicatedLineId(exchange);
|
||||
String secretKey = dedicatedLineService.getPairCodeSecretKey(dedicatedLineId);
|
||||
String ts = WebUtils.getDedicatedLineTimestamp(exchange);
|
||||
String sign = WebUtils.getDedicatedLineSign(exchange);
|
||||
if (validateSign(dedicatedLineId, ts, sign, secretKey)) {
|
||||
// Go to next plugin
|
||||
Mono next = FizzPluginFilterChain.next(exchange);
|
||||
return next.defaultIfEmpty(ReactorUtils.NULL).flatMap(nil -> {
|
||||
doAfter();
|
||||
return Mono.empty();
|
||||
});
|
||||
} else {
|
||||
// Auth failed
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
response.setStatusCode(HttpStatus.UNAUTHORIZED);
|
||||
response.getHeaders().setCacheControl("no-store");
|
||||
response.getHeaders().setExpires(0);
|
||||
String respJson = WebUtils.jsonRespBody(HttpStatus.UNAUTHORIZED.value(),
|
||||
HttpStatus.UNAUTHORIZED.getReasonPhrase(), traceId);
|
||||
return WebUtils.response(exchange, HttpStatus.UNAUTHORIZED, null, respJson);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("{} {} Exception", traceId, DEDICATED_LINE_PAIRING_PLUGIN_FILTER, e, LogService.BIZ_ID, traceId);
|
||||
String respJson = WebUtils.jsonRespBody(HttpStatus.INTERNAL_SERVER_ERROR.value(),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase(), traceId);
|
||||
return WebUtils.response(exchange, HttpStatus.INTERNAL_SERVER_ERROR, null, respJson);
|
||||
}
|
||||
}
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, Map<String, Object> config) {
|
||||
String traceId = WebUtils.getTraceId(exchange);
|
||||
try {
|
||||
LogService.setBizId(traceId);
|
||||
String dedicatedLineId = WebUtils.getDedicatedLineId(exchange);
|
||||
String secretKey = dedicatedLineService.getPairCodeSecretKey(dedicatedLineId);
|
||||
String ts = WebUtils.getDedicatedLineTimestamp(exchange);
|
||||
String sign = WebUtils.getDedicatedLineSign(exchange);
|
||||
if (validateSign(dedicatedLineId, ts, sign, secretKey)) {
|
||||
// Go to next plugin
|
||||
Mono next = FizzPluginFilterChain.next(exchange);
|
||||
return next.defaultIfEmpty(ReactorUtils.NULL).flatMap(nil -> {
|
||||
doAfter();
|
||||
return Mono.empty();
|
||||
});
|
||||
} else {
|
||||
// Auth failed
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
response.setStatusCode(HttpStatus.UNAUTHORIZED);
|
||||
response.getHeaders().setCacheControl("no-store");
|
||||
response.getHeaders().setExpires(0);
|
||||
String respJson = WebUtils.jsonRespBody(HttpStatus.UNAUTHORIZED.value(),
|
||||
HttpStatus.UNAUTHORIZED.getReasonPhrase(), traceId);
|
||||
return WebUtils.response(exchange, HttpStatus.UNAUTHORIZED, null, respJson);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("{} {} Exception", traceId, DEDICATED_LINE_PAIRING_PLUGIN_FILTER, LogService.BIZ_ID, traceId, e);
|
||||
String respJson = WebUtils.jsonRespBody(HttpStatus.INTERNAL_SERVER_ERROR.value(),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase(), traceId);
|
||||
return WebUtils.response(exchange, HttpStatus.INTERNAL_SERVER_ERROR, null, respJson);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean validateSign(String dedicatedLineId, String ts, String sign, String secretkey) {
|
||||
if (StringUtils.isBlank(dedicatedLineId) || StringUtils.isBlank(ts) || StringUtils.isBlank(sign)
|
||||
|| StringUtils.isBlank(secretkey)) {
|
||||
return false;
|
||||
}
|
||||
private boolean validateSign(String dedicatedLineId, String ts, String sign, String secretkey) {
|
||||
if (StringUtils.isBlank(dedicatedLineId) || StringUtils.isBlank(ts) || StringUtils.isBlank(sign)
|
||||
|| StringUtils.isBlank(secretkey)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// SHA256(dedicatedLineId+_+ts+_+secretkey)
|
||||
String data = dedicatedLineId + "_" + ts + "_" + secretkey;
|
||||
if (!DigestUtils.sha256Hex(data).equals(sign)) {
|
||||
return false;
|
||||
}
|
||||
// SHA256(dedicatedLineId+_+ts+_+secretkey)
|
||||
String data = dedicatedLineId + "_" + ts + "_" + secretkey;
|
||||
if (!DigestUtils.sha256Hex(data).equals(sign)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// validate timestamp
|
||||
long t = 0;
|
||||
try {
|
||||
t = Long.valueOf(ts).longValue();
|
||||
} catch (Exception e) {
|
||||
log.warn("invalid timestamp: {}", ts);
|
||||
return false;
|
||||
}
|
||||
long now = System.currentTimeMillis();
|
||||
long offset = 5 * 60 * 1000;
|
||||
if (t < now - offset || t > now + offset) {
|
||||
log.warn("timestamp expired: {}", ts);
|
||||
return false;
|
||||
}
|
||||
// validate timestamp
|
||||
long t = 0;
|
||||
try {
|
||||
t = Long.valueOf(ts).longValue();
|
||||
} catch (Exception e) {
|
||||
log.warn("invalid timestamp: {}", ts);
|
||||
return false;
|
||||
}
|
||||
long now = System.currentTimeMillis();
|
||||
long offset = 5 * 60 * 1000;
|
||||
if (t < now - offset || t > now + offset) {
|
||||
log.warn("timestamp expired: {}", ts);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void doAfter() {
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void doAfter() {
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user