gateway获取请求体和响应体
GateWay 获取响应结果,处理大数据分段传输问题
GlobalCacheRequestFilter
package com.yymt.project.filter;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.yymt.project.config.SwaggerProvider;
import com.yymt.project.feign.AuthFeignClient;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;
import org.reactivestreams.Publisher;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
@Component
public class GlobalCacheRequestFilter implements GlobalFilter, Ordered {
public final static String CACHED_REQUEST_PARAM_KEY = "CACHED_REQUEST_PARAM_KEY";
public final static String SYS_LOG_ID = "sysLogId";
public final static Snowflake snowflake = IdUtil.getSnowflake(1, 1);
private int order;
@Resource
AuthFeignClient authFeignClient;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
HttpHeaders headers = request.getHeaders();
String sysLogId = String.valueOf(snowflake.nextId());
Object cachedRequestBodyObject = exchange.getAttributeOrDefault(CACHED_REQUEST_PARAM_KEY,
null);
if (cachedRequestBodyObject != null) {
return chain.filter(exchange);
}
String contentType = exchange.getRequest().getHeaders().getFirst("Content-Type");
if (StrUtil.isNotBlank(contentType) && contentType.contains(MediaType.APPLICATION_JSON_VALUE)) {
return DataBufferUtils.join(exchange.getRequest().getBody()).map(dataBuffer -> {
byte[] bytes = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(bytes);
DataBufferUtils.release(dataBuffer);
return bytes;
}).defaultIfEmpty(new byte[0])
.doOnNext(bytes -> {
String param = new String(bytes, StandardCharsets.UTF_8);
logtrace(exchange, param);
exchange.getAttributes().put(CACHED_REQUEST_PARAM_KEY, param);
exchange.getAttributes().put(SYS_LOG_ID, sysLogId);
}).then(chain.filter(exchange.mutate().response(recordResponseLog(exchange)).build()));
}
Map m = request.getQueryParams();
String param = Convert.toStr(m);
logtrace(exchange, param);
exchange.getAttributes().put(CACHED_REQUEST_PARAM_KEY, param);
exchange.getAttributes().put(SYS_LOG_ID, sysLogId);
return chain.filter(exchange.mutate().response(recordResponseLog(exchange)).build());
}
@Override
public int getOrder() {
return this.order;
}
public GlobalCacheRequestFilter() {
this.order = -30;
}
public GlobalCacheRequestFilter(int order) {
this.order = order;
}
private void logtrace(ServerWebExchange exchange, String param) {
ServerHttpRequest serverHttpRequest = exchange.getRequest();
String path = serverHttpRequest.getURI().getPath();
String method = serverHttpRequest.getMethodValue();
String headers = serverHttpRequest.getHeaders().entrySet()
.stream()
.map(entry -> " " + entry.getKey() + ": [" + String.join(";", entry.getValue()) + "]")
.collect(Collectors.joining("\n"));
log.debug("\n" + "------------------------------------------------>>\n" +
"HttpMethod : {}\n" +
"Uri : {}\n" +
"Param : {}\n" +
"Headers : \n" +
"{}\n" +
"\"<<------------------------------------------------"
, method, path, param, headers);
}
private ServerHttpResponseDecorator recordResponseLog(ServerWebExchange exchange) {
ServerHttpResponse response = exchange.getResponse();
HttpHeaders headers = exchange.getRequest().getHeaders();
MediaType mediaType = headers.getContentType();
String url = exchange.getRequest().getURI().getPath();
DataBufferFactory bufferFactory = response.bufferFactory();
ServerHttpResponseDecorator decoratorResponse = new ServerHttpResponseDecorator(response) {
@Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
if (body instanceof Flux) {
if (StrUtil.isBlank(headers.getFirst("Authorization"))) {
return super.writeWith(body);
}
if ((mediaType != null && mediaType.equals(MediaType.MULTIPART_FORM_DATA))
|| (mediaType != null && mediaType.equals(MediaType.APPLICATION_FORM_URLENCODED))) {
return super.writeWith(body);
}
if (url.contains(SwaggerProvider.API_URI)) {
return super.writeWith(body);
}
Flux<? extends DataBuffer> fluxBody = Flux.from(body);
return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
StringBuilder bodyString = new StringBuilder();
dataBuffers.forEach(dataBuffer -> {
byte[] content = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(content);
DataBufferUtils.release(dataBuffer);
bodyString.append(new String(content, CharsetUtil.UTF_8));
});
String result = bodyString.toString();
byte[] uppedContent = new String(result.getBytes(), CharsetUtil.UTF_8).getBytes();
sysLogResAdd(exchange, result);
response.getHeaders().setContentLength(uppedContent.length);
return bufferFactory.wrap(uppedContent);
}));
}
return super.writeWith(body);
}
};
return decoratorResponse;
}
private void sysLogResAdd(ServerWebExchange exchange, String result) {
String sysLogId = exchange.getAttributeOrDefault(GlobalCacheRequestFilter.SYS_LOG_ID, "");
log.info("===============sysLogId:{},responseResult:{}", sysLogId, result);
Map<String, Object> sysLogResMap = new HashMap<>();
sysLogResMap.put("id", sysLogId);
sysLogResMap.put("result", result);
authFeignClient.sysLogResAdd(sysLogResMap);
}
}
AuthorityFilter
package com.yymt.project.filter;
import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yymt.project.dto.HasPermissionReqDTO;
import com.yymt.project.entity.User;
import com.yymt.project.entity.common.CodeEnum;
import com.yymt.project.entity.common.Result;
import com.yymt.project.feign.AuthFeignClient;
import com.yymt.project.filter.util.ModifiedRequestDecorator;
import com.yymt.project.filter.util.RecorderServerHttpRequestDecorator;
import com.yymt.project.filter.util.RewriteConfig;
import com.yymt.project.filter.util.SensitiveWordUtils;
import com.yymt.project.util.IpUtil;
import com.yymt.project.util.JwtUtil;
import com.yymt.project.util.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import javax.annotation.Resource;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
@Slf4j
@Component
public class AuthorityFilter implements GlobalFilter, Ordered {
@Resource
AuthFeignClient authFeignClient;
@Resource
SensitiveWordUtils sensitiveWordUtils;
@Value("${access.whitelist}")
private String whitelist;
@Value("${access.sensitiveWordFilterUrl:}")
private String sensitiveWordFilterUrl;
private static final String OPTIONS = "OPTIONS";
@Resource
RedisUtils redisUtils;
public static String REDIS_IP_LIST_KEY = "ip_list_key:";
public static String REDIS_IP_LIST_TYPE_KEY = "ip_list_type_key:";
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String path = exchange.getRequest().getPath().toString();
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
HttpHeaders headers = exchange.getRequest().getHeaders();
String token = headers.getFirst("Authorization");
String requestHeaderVersion = headers.getFirst("version");
String contentType = headers.getFirst("Content-Type");
Integer version = null;
JSONObject bodyObject = null;
if ((request.getMethod() == HttpMethod.POST || request.getMethod() == HttpMethod.PUT) && "application/json".equals(contentType)) {
AtomicReference<String> requestBody = new AtomicReference<>("");
RecorderServerHttpRequestDecorator requestDecorator = new RecorderServerHttpRequestDecorator(request);
Flux<DataBuffer> body = requestDecorator.getBody();
body.subscribe(buffer -> {
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
requestBody.set(charBuffer.toString());
});
String bodyString = requestBody.get();
if (StringUtils.isNotBlank(bodyString) && bodyString.startsWith("{")) {
bodyObject = JSONObject.parseObject(bodyString);
}
}
if (StringUtils.isNotBlank(requestHeaderVersion)) {
version = Integer.valueOf(requestHeaderVersion);
} else if (bodyObject != null) {
if (bodyObject.getInteger("version") != null) {
version = bodyObject.getInteger("version");
}
}
if (StringUtils.isNotBlank(token)) {
version = JwtUtil.getVersion(token);
}
if (version == null) {
version = 1;
}
String ip = IpUtil.getIpAddress(exchange.getRequest());
boolean needCheckIp = false;
if (StringUtils.isNotBlank(token)) {
if (JwtUtil.getUserId(token).longValue() != 1 && JwtUtil.getLoginMode(token) == 1) {
needCheckIp = true;
}
} else if (bodyObject != null) {
if (bodyObject.getInteger("loginMode") != null) {
if (bodyObject.getInteger("loginMode") == 1) {
needCheckIp = true;
}
}
}
if (needCheckIp) {
String ipListType = redisUtils.get(REDIS_IP_LIST_TYPE_KEY + version);
String ipList = redisUtils.get(REDIS_IP_LIST_KEY + version);
if (StringUtils.isNotBlank(ipListType) && StringUtils.isNotBlank(ipList)) {
String[] ipRuleArr = ipList.split(",");
if ("1".equals(ipListType)) {
for (String ipRule : ipRuleArr) {
if (IpUtil.checkIpByRule(ip, ipRule)) {
response.setStatusCode(HttpStatus.LOCKED);
Result result = new Result().setCode(HttpStatus.LOCKED.value()).setMsg("ip已被禁用");
DataBuffer buffer = response.bufferFactory().wrap(JSON.toJSONString(result).getBytes());
return response.writeWith(Mono.just(buffer));
}
}
}
if ("0".equals(ipListType)) {
boolean isAllow = false;
for (String ipRule : ipRuleArr) {
if (IpUtil.checkIpByRule(ip, ipRule)) {
isAllow = true;
break;
}
}
if (!isAllow) {
response.setStatusCode(HttpStatus.LOCKED);
Result result = new Result().setCode(HttpStatus.LOCKED.value()).setMsg("ip已被禁用");
DataBuffer buffer = response.bufferFactory().wrap(JSON.toJSONString(result).getBytes());
return response.writeWith(Mono.just(buffer));
}
}
}
}
String params = "none";
String sysLogId = "";
try {
params = exchange.getAttributeOrDefault(GlobalCacheRequestFilter.CACHED_REQUEST_PARAM_KEY, "none");
sysLogId = exchange.getAttributeOrDefault(GlobalCacheRequestFilter.SYS_LOG_ID, "");
if (params != null) {
exchange.getAttributes().remove(params);
}
} catch (Exception e) {
log.error("get params error!");
}
String[] whites = whitelist.split(",");
boolean flag = false;
for (String white : whites) {
if (path.indexOf(white) != -1) {
flag = true;
break;
}
}
List<String> filterUrlList = Arrays.asList(sensitiveWordFilterUrl.split(","));
if (flag) {
if (filterUrlList.contains(path)) {
if (request.getMethod() == HttpMethod.POST || request.getMethod() == HttpMethod.PUT) {
return new ModifiedRequestDecorator(exchange, new RewriteConfig()
.setRewriteFunction(String.class, String.class, (ex, requestData)
-> Mono.just(sensitiveWordUtils.replaceWord(requestData))
)).filter(exchange, chain);
} else {
return chain.filter(exchange);
}
} else {
return chain.filter(exchange);
}
}
if (StringUtils.isNotBlank(token)) {
Result successResult = null;
try {
HasPermissionReqDTO reqDTO = new HasPermissionReqDTO().setToken(token).setUrl(path)
.setServiceName(path.split("/")[1]).setIp(ip).setParams(params)
.setSysLogId(Convert.toLong(sysLogId));
successResult = authFeignClient.hasPermission(reqDTO);
} catch (Exception e) {
log.error("鉴权服务异常!", e);
response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
Result result = new Result().setCode(HttpStatus.INTERNAL_SERVER_ERROR.value()).setMsg("鉴权服务异常");
DataBuffer buffer = response.bufferFactory().wrap(JSON.toJSONString(result).getBytes());
return response.writeWith(Mono.just(buffer));
}
if (ObjectUtils.isEmpty(successResult) || CodeEnum.TOKEN_EXPIRE.getCode().equals(successResult.getCode())) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
Result result = new Result().setCode(HttpStatus.UNAUTHORIZED.value()).setMsg("登录已过期,请重新登录");
DataBuffer buffer = response.bufferFactory().wrap(JSON.toJSONString(result).getBytes());
return response.writeWith(Mono.just(buffer));
} else if (CodeEnum.SUCCESS.getCode().equals(successResult.getCode())) {
User data = JSON.parseObject(JSON.toJSONString(successResult.getData()), User.class);
ServerHttpRequest host = exchange.getRequest().mutate().header("x-user-id", data.getUserId().toString())
.header("x-user-mobile", data.getMobile()).header("Authorization", token)
.header("admin", data.getAdmin().toString())
.header("user-type", data.getUserType() == null ? "" : data.getUserType().toString())
.header("system-version", String.valueOf(version))
.header("communityId", data.getCommunityId() == null ? "" : data.getCommunityId().toString())
.header("communityIds", StringUtils.join(data.getCommunityIds().toArray(), ",")).build();
ServerWebExchange build = exchange.mutate().request(host).build();
if (filterUrlList.contains(path)) {
if (request.getMethod() == HttpMethod.POST || request.getMethod() == HttpMethod.PUT) {
return new ModifiedRequestDecorator(build, new RewriteConfig()
.setRewriteFunction(String.class, String.class, (ex, requestData)
-> Mono.just(requestData == null ? "" : sensitiveWordUtils.replaceWord(requestData))
)).filter(build, chain);
} else {
return chain.filter(build);
}
} else {
return chain.filter(build);
}
} else if (CodeEnum.FORBIDDEN.getCode().equals(successResult.getCode())) {
response.setStatusCode(HttpStatus.FORBIDDEN);
Result result = new Result().setCode(HttpStatus.FORBIDDEN.value()).setMsg("无权限,请联系管理员!");
DataBuffer buffer = response.bufferFactory().wrap(JSON.toJSONString(result).getBytes());
return response.writeWith(Mono.just(buffer));
} else if (CodeEnum.REMOTE_LOGIN.getCode().equals(successResult.getCode())) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
Result result = new Result().setCode(HttpStatus.UNAUTHORIZED.value())
.setMsg(CodeEnum.REMOTE_LOGIN.getMsg());
DataBuffer buffer = response.bufferFactory().wrap(JSON.toJSONString(result).getBytes());
return response.writeWith(Mono.just(buffer));
} else {
response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
Result result = new Result().setCode(HttpStatus.INTERNAL_SERVER_ERROR.value())
.setMsg(CodeEnum.COMMON_ERROR.getMsg());
DataBuffer buffer = response.bufferFactory().wrap(JSON.toJSONString(result).getBytes());
return response.writeWith(Mono.just(buffer));
}
}
response.setStatusCode(HttpStatus.UNAUTHORIZED);
Result result = new Result().setCode(HttpStatus.UNAUTHORIZED.value())
.setMsg("登录已过期,请重新登录");
DataBuffer buffer = response.bufferFactory().wrap(JSON.toJSONString(result).getBytes());
return response.writeWith(Mono.just(buffer));
}
@Override
public int getOrder() {
return 0;
}
}