通过SpringCloudGateway中的GlobalFilter实现鉴权过滤

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 {

    @Resource
    private MerchantAppApi merchantAppApi;

    /**
     * 签名算法
     */
    private final static String SIGN_RULE = "HmacSHA256";

    /**
     * 通过sdkKey做鉴权过滤
     *
     **/
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 获取头信息
        HttpHeaders headers = exchange.getRequest().getHeaders();
        // 头信息 客户端签名
        String sign = headers.getFirst("sign");
        // 头信息 客户端timeStamp
        String timeStamp = headers.getFirst("timeStamp");
        // 头信息 账户key
        String sdkKey = headers.getFirst("sdkKey");
        //获取body str
        String 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);
            // 200
            response.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 排序
     */
    @Override
    public 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;
    }

}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值