FeignClient传入的header中带逗号引发的401问题

问题:

FeignClient代码

   
@FeignClient(name = "xxx",url = "https://xxxx:1234", configuration = UcFeignConfiguration.class)
@Headers("Content-Type: application/json;charset=utf-8")
public interface UcAgent {
 /**
     * 按条件获取员工并分页
     *
     * @param authHeader
     * @param staffQueryMap
     */
    @GetMapping("/staff/v1/staffs")
    List<StaffIdPo> getStaffsWithFilterFilterPartially(
            @RequestHeader("Authorization") String authHeader,
            @SpringQueryMap Map<String,Object> staffQueryMap);

}
UcFeignConfiguration
@Slf4j
public class UcFeignConfiguration {

    private static final String PER_FIX = "Load balancer does not contain an instance";
    private static final String UNKNOWN_ERROR = "unknown error";
    private static final Integer ERROR_CODE = 59;
    private static final Integer HTTP_STATUS_OK = 200;
    private static final Integer HTTP_NOT_FOUND = 404;

    @Bean
    public ErrorDecoder errorDecoder() {
        return new UcErrorDecoder();
    }


    public class UcErrorDecoder implements ErrorDecoder {
        @Override
        public Exception decode(String methodKey, Response response) {
            ErrorDetail errorDetail = new ErrorDetail();
            if (response.status() != HTTP_STATUS_OK) {
                log.info("response request:{}, body:{}, http status:{}", response.request(), response.body(), response.status());
                try {
                    char[] buffer = new char[response.body().length()];
                    IOUtils.read(response.body().asReader(StandardCharsets.UTF_8), buffer);
                    String responseBody = new String(buffer);
                    if (StringUtils.startsWith(responseBody, PER_FIX) && StringUtils.length(responseBody) > ERROR_CODE) {
                        errorDetail.setDescription(StringUtils.substring(responseBody, ERROR_CODE) + " not exists");
                        throw new BaseException(HttpStatus.UNAVAILABLE, errorDetail);
                    }

                    ErrorResult result = JsonUtils.toObject(responseBody, ErrorResult.class);
                    log.info("uc api exception result error:{},response:{},response status:{}", JsonUtils.toString(result),
                            responseBody, response.status());
                    if (Objects.nonNull(result)) {
                        return dealUcApiException(response, responseBody);
                    } else if (response.status() == HTTP_NOT_FOUND) {
                        throw new UcApiException(404, UNKNOWN_ERROR);
                    } else {
                        errorDetail.setDescription(UNKNOWN_ERROR);
                        throw new BaseException(HttpStatus.UNKNOWN, errorDetail);
                    }
                } catch (IOException e) {
                    log.error("handle error exception:{}", e);
                    throw new BaseException(HttpStatus.UNKNOWN, errorDetail);
                }
            }
            throw new BaseException(com.qax.pylon.commons.constant.HttpStatus.UNAVAILABLE, errorDetail);
        }

    
    }

}

构建header的方法

    /**
     * 构建请求头header
     * todo 2.4
     *
     * @return
     */
    public String buildAuthHeader() {
        long nonce = Long.parseLong(RandomUtil.randomNumbers(10));
        long timestamp = System.currentTimeMillis();
        final String signature = SignUtil.generateSignature(appKey, secret, timestamp, nonce);

        return "TEST-HMAC-SHA256 appKey=" + appKey +
                ",nonce=" + nonce +
                ",timestamp=" + timestamp +
                ",version=1.2.0" +
                ",signature=" + signature;
    }

可以看到构建的header字符串带了逗号,然后发起get请求调用接口,错误日志如下:

response request:GET https://xxxx:1234/staff/v1/staffs:filter-filter-partially?filter_filter.asset_id.id=232323&offset=0&limit=10&keyword&filter_filter.asset_id.oid=23232323 HTTP/1.1
Authorization: TEST-HMAC-SHA256 appKey=XXXXX, nonce=6291065565, timestamp=1644836211277, version=1.2.0, signature=fdfdsfdfdfdfdf
Binary data, body:null, http status:401

header错误导致鉴权失败;

debug到feign.template.HeaderTemplate类下的expand方法

    public String expand(Map<String, ?> variables) {
        String result;
        for(result = super.expand(variables); result.endsWith(","); result = result.replaceAll(",$", "")) {
        }

        result = result.replaceAll(",", ", ");
        return result;
    }

可以看到此方法会将header中的逗号替换,替换后的内容是逗号+空格,使用被替换的header发起请求调用其他服务,其他服务在接受到请求后,解析header中的数据的时候出错导致鉴权失败;

解决:使用拦截器替换请求头

@Configuration
@Slf4j
public class FeignConfig implements RequestInterceptor {

    private static final String HEADER_KEY = "Authorization";

    @Override
    public void apply(RequestTemplate requestTemplate) {
        Map<String, Collection<String>> headersMap = requestTemplate.headers();

        Collection<String> headers = headersMap.get(HEADER_KEY);
        headers.stream().forEach(header -> {
            if (StringUtils.isNotBlank(header)
                    && header.startsWith("TEST-HMAC-SHA256")
                    && header.contains(", ")) {
                requestTemplate.removeHeader(HEADER_KEY);
                requestTemplate.header(HEADER_KEY, header.replaceAll(", ", ","));
            }
        });
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值