1.pom.xml中加入gateway jar包
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency>
2.创建权限过滤器 SecurityFilter
/*** 鉴权过滤***/
@Slf4j
@Component
public class SecurityFilter implements GlobalFilter, Ordered {@Resourceprivate MerchantAppApi merchantAppApi;/*** 签名算法*/private final static String SIGN_RULE = "HmacSHA256";/*** 通过sdkKey做鉴权过滤***/@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 获取头信息HttpHeaders headers = exchange.getRequest().getHeaders();// 头信息 客户端签名String sign = headers.getFirst("sign");// 头信息 客户端timeStampString timeStamp = headers.getFirst("timeStamp");// 头信息 账户keyString sdkKey = headers.getFirst("sdkKey");//获取body strString bodyStr = RequestBodyUtil.resolveBodyFromRequest(exchange.getRequest());// 去空格bodyStr = StringUtils.replace(bodyStr, " ", "");String authDesc = "鉴权异常..";try {// rpc 账户信息GetMerchantAppResp merchantApp = merchantAppApi.getMerchantApp(new MerchantAppReq().setSdkKey(sdkKey)).getData();if (merchantApp == null) {authDesc = "账户不存在..";throw new IllegalAccessException("账户不存在..");}if (!merchantApp.getStatus()) {authDesc = "账户被禁用..";throw new IllegalAccessException("账户被禁用..");}// 验证签名String signStr = SecurityFilter.genSign(timeStamp, sdkKey, merchantApp.getSdkSecret(), bodyStr);if (!StringUtils.equals(sign, signStr)) {authDesc = "签名验证失败..";throw new IllegalAccessException("签名验证失败..");}} catch (Exception e) {log.error(String.format("=== %s ===, timeStampStr=%s, sdkKey=%s, requestBody=%s",authDesc, timeStamp, sdkKey, bodyStr), e);ServerHttpResponse response = exchange.getResponse();ApiResp apiResp = ApiResp.authFail(authDesc);byte[] bits = JacksonUtil.toJsonString(apiResp).getBytes(StandardCharsets.UTF_8);DataBuffer buffer = response.bufferFactory().wrap(bits);// 200response.setStatusCode(HttpStatus.OK);//指定编码,否则在浏览器中会中文乱码response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");return response.writeWith(Mono.just(buffer));}return chain.filter(exchange);}/*** 根据请求时间戳 以及请求body 生产签名** @param timeStamp 时间戳* @param bodyStr 实体类* @return 签名*/private static String genSign(String timeStamp, String sdkKey, String sdkSecret, String bodyStr) {String sign = "";try {String signResource = timeStamp + sdkKey + bodyStr;Mac mac = Mac.getInstance(SIGN_RULE);mac.init(new SecretKeySpec(sdkSecret.getBytes(StandardCharsets.UTF_8), SIGN_RULE));byte[] signatureBytes = mac.doFinal(signResource.getBytes(StandardCharsets.UTF_8));String hexStr = Hex.encodeHexString(signatureBytes);sign = Base64.encodeBase64String(hexStr.getBytes());} catch (Exception e) {log.error("=== 生成签名失败 ===, timeStampStr={}, sdkKey={}, sdkSecret={}, requestBody={}", timeStamp, sdkKey, sdkSecret, bodyStr);}return sign;}/*** 过滤顺序** @return 排序*/@Overridepublic int getOrder() {return 5;}}
3.封装工具类 RequestBodyUtil
/*** 操作request body的工具**/
public class RequestBodyUtil {private final static Pattern P = Pattern.compile("\\s*|\t|\r|\n");/*** 读取body内容** @param serverHttpRequest 请求对象* @return body*/public static String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) {//获取请求体Flux<DataBuffer> body = serverHttpRequest.getBody();StringBuilder sb = new StringBuilder();body.subscribe(buffer -> {byte[] bytes = new byte[buffer.readableByteCount()];buffer.read(bytes);String bodyString = new String(bytes, StandardCharsets.UTF_8);sb.append(bodyString);});return formatStr(sb.toString());}/*** 去掉空格,换行和制表符** @param str 待优化字符串* @return 格式化后的str*/private static String formatStr(String str) {if (str != null && str.length() > 0) {Matcher m = P.matcher(str);return m.replaceAll("");}return str;}}