filter实现接口验签流程+保证body请求体不丢失

接口验签流程

  1. 接收前端传来的入参,并根据入参的key通过ASCII码进行排序(放到treeMap即可)
  2. 将排序好的json字符创进行md5摘要。(将sign字段去除)
  3. 将排序好的字符串与前端传入的sign字段进行比对,如果正确,继续,错误返回错误信息

存在的问题(body丢失,所有post请求失效)

  1. 从HttpServletRequest获取的InputStream读一次就无法再读了
    解决办法:将inputStream通过 extends HttpServletRequestWrapper进行inputStream的包装,让inputStream从ByteArrayInputStream中进行流的读取,该对象可以从内存中进行数据的读取,不会读取一次之后就无法再读了。
    1.请求体存在流中,保证后面可以读取到请求体,需要复制流
    2.inputStream的读取方式为:会有一个pos指针,他指示每次读取之后下一次要读取的起始位置,当读到最后一个字符的时候,pos指针不会重置
    3.但不是所有的流都是这种读取方式,ByteArrayInputStream 就是从内存中读取byte[],每次读取都会重新遍历。就像遍历List时,会新建一个
    Iterator,所以pos也就回到了开始的位置。
  2. 未理解的点?
    为什么在复制流的时候,要从流中read出来,在write出去,而不能直接使用httpservlet.getInputStream。

代码实现过程

  1. 实现过滤器接口
  2. 重写doFilter方法
  3. 新建类继承HttpServletRequestWrapper,Stream.copyInputStream。copy出一个字节数组。重写getInputStream()和getReader(),改为内存读取流,保证body不丢失
  4. 获取url上和body中的参数,并通过treemap进行排序
  5. 对map中的数据进行除了sign字段的摘要
  6. 与前端传入的md5摘要进行比对

代码实现

@Slf4j
@WebFilter(urlPatterns = {
   "/user"})
public class SignAuthFilter implements Filter {
   

    @Override
    public void init(FilterConfig filterConfig) {
   
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
   

        HttpServletResponse response = (HttpServletResponse) res;
        // 防止流读取一次后就没有了, 所以需要将流继续写出去
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(request);

        //获取全部参数(包括URL和body上的)
        SortedMap<String, String> allParams = HttpUtils.getAllParams(requestWrapper);
        //获取时间为空
        String currentTime = allParams.get(Constant.System.SIGN_TIME);
        if (StringUtils.isBlank(currentTime)) {
   
            log.error("current_time字段为空,验签失败,param:{}", JSON.toJSONString(allParams));
            HttpUtils.setResponsemessage(response, "参数异常");
            return;
        }
        //对参数时间进行验证 超时
        boolean isTimeOut = SignUtil.verifyStayTime(currentTime);
        if (Boolean.FALSE.equals(isTimeOut)) {
   
            log.error("页面停留时间过长,请重新提交,param:{}", JSON.toJSONString(allParams));
            HttpUtils.setResponsemessage(response, "页面停留时间过长,请重新提交");
            return;
        }
        //对参数进行签名验证
        boolean isSigned = SignUtil.verifySign(allParams);
        if (isSigned) {
   
            chain.doFilter(requestWrapper, response);
        } else {
   
            log.error("验签失败,param:{}", JSON.toJSONString(allParams));
            HttpUtils.setResponsemessage(response, "参数异常");
        }
    }


    @Override
    public void 
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值