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