栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

RestTemplate拦截器中统一追加报文签名

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

RestTemplate拦截器中统一追加报文签名

在本空间有一文章,描述了如何通过Postman工具自动添加请求报文的签名。其请求报文格式及签名位置参考《报文格式》

现同样,如果我们调用某平台,对方平台也要求我们调用时必须有签名,以防止报文中途被篡改。下面给出普通性做法。本例以SpringBoot为基础。

下面是拦截器的实现。

package com.ule.xxx.thrsp.comm;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.NamevaluePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.message.BasicNamevaluePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Component;

import com.ule.xxx.config.ThrPlatInfoConfig;
import com.ule.xxx.config.ThrPlatInfoConfig.ThrPlatConfigProp;
import com.ule.xxx.openapi.constant.CommResultCode;
import com.ule.xxx.openapi.exception.BussinessException;
import com.ule.xxx.utils.MDUtils;


@Component(value = "toThrPlatSignInterceptor")
public class ToThrPlatSignInterceptor implements ClientHttpRequestInterceptor {
    
    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
            throws IOException {

        String bodyStr = new String(body, StandardCharsets.UTF_8);
        // 生成签名并添加到paramters中
        try {
            request = addSignInURI(request, bodyStr);
        }
        catch (URISyntaxException e) {
            // Ingore
        }
        return execution.execute(request, body);
    }

    private HttpRequest addSignInURI(HttpRequest request, String bodyStr) throws IOException, URISyntaxException {
        URI uri = request.getURI();
        TreeMap urlParamMap = handleUri(uri);
        String sign = getSign(urlParamMap, bodyStr);

        ClientHttpRequest clientRequest = (ClientHttpRequest) request;
        List params = new ArrayList<>();
        params.add(new BasicNamevaluePair("sign", sign));
        String url = URLEncodedUtils.format(params, "UTF-8");
        URI src = new URI(request.getURI().toString().concat("&").concat(url));
        clientRequest = new HttpComponentsClientHttpRequestFactory().createRequest(src, request.getMethod());
        return clientRequest;
    }

    private TreeMap handleUri(URI uri) {
        TreeMap urlMap = new TreeMap<>();
        try {
            String rawQuery = uri.getRawQuery();
            if (StringUtils.isNotEmpty(rawQuery)) {
                String queryParams = URLDecoder.decode(rawQuery, "utf-8");
                String[] params = queryParams.split("&", -1);
                for (int i = 0; i < params.length; i++) {
                    String[] paramPair = params[i].split("=");
                    if (paramPair.length == 2 && !"sign".equals(paramPair[0])) {
                        urlMap.put(paramPair[0], paramPair[1]);
                    }
                }
            }
        }
        catch (UnsupportedEncodingException e) {
            logger.error("UnsupportedEncodingException", e);
        }
        return urlMap;
    }

    @Autowired
    private ThrPlatInfoConfig thrPlatInfoConfig;

    private String getSign(TreeMap urlParamMap, String bodyStr) {
        String thirdId = null;
        // 签名原文PartA:
        StringBuilder signSource = new StringBuilder();
        // 除去sign的地址请求参数列表拼接而成的字符串
        int i = 0;
        for (Map.Entry entry : urlParamMap.entrySet()) {
            String paramKey = entry.getKey();
            if ("thirdId".equals(paramKey)) {
                thirdId = entry.getValue();
            }
            if (i > 0) {
                signSource.append("&");
            }
            if (StringUtils.isNoneBlank(entry.getValue())) {
                signSource.append(paramKey).append("=").append(entry.getValue());
            }
            i++;
        }

        if (StringUtils.isEmpty(thirdId)) {
            throw new BussinessException(CommResultCode.SYSTEM_ERROR);
        }

        // 根据三方平台ID获取对应的三方平台发放与我们的密钥
        ThrPlatConfigProp thrPlatConfigInfo = thrPlatInfoConfig.getConfigByCustId(thirdId);
        if (thrPlatConfigInfo == null) {
            throw new BussinessException(CommResultCode.SYSTEM_ERROR);
        }
        String meAppSecret = thrPlatConfigInfo.getMySecret();
        if (StringUtils.isEmpty(meAppSecret)) {
            throw new BussinessException(CommResultCode.SYSTEM_ERROR);
        }

        // 签名原文PartB:
        signSource.append(uleAppSecret);

        // 签名原文PartC:
        if (StringUtils.isNotBlank(bodyStr)) {
            signSource.append(bodyStr);
        }

        try {
            return MDUtils.md5EncodeForHex(signSource.toString(), "utf-8");
        }
        catch (UnsupportedEncodingException e) {
            logger.error("UTF-8 is unsupported", e);
            throw new BussinessException(CommResultCode.SYSTEM_ERROR);
        }
        catch (NoSuchAlgorithmException e) {
            logger.error("MessageDigest不支持MD5", e);
            throw new BussinessException(CommResultCode.SYSTEM_ERROR);
        }
    }

}

拦截器在请求创建时加入。下面给出示例。

    
    @Bean(name = "thrRestTemplate")
    public RestTemplate thrRestTemplate(@Qualifier("requestFactory") ClientHttpRequestFactory requestFactory) {

        RestTemplate restTemplate = new RestTemplate(requestFactory);
        List> converterList = restTemplate.getMessageConverters();

        // 重新设置StringHttpMessageConverter字符集为UTF-8,解决中文乱码问题
        HttpMessageConverter converterTarget = null;
        for (HttpMessageConverter item : converterList) {
            if (StringHttpMessageConverter.class == item.getClass()) {
                converterTarget = item;
                break;
            }
        }
        if (null != converterTarget) {
            converterList.remove(converterTarget);
        }
        // 都是JSON报文
        converterList.add(1, fastJsonHttpMessageConverter);

        // 设置错误处理器
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler());

        // 设置拦截器,添加共通签名至URI参数中
        ArrayList interceptors = new ArrayList<>();
        interceptors.add(httpRequestInterceptor);
        restTemplate.setInterceptors(interceptors);

        return restTemplate;
    }

    @Resource(name = "toThrPlatSignInterceptor")
    private ClientHttpRequestInterceptor httpRequestInterceptor;

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/425578.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号