关于统一处理http请求安全验证遇到media type不同导致处理失败问题

最近碰到一个需求是要模仿支付宝、微信等平台的API接口。在APP登录时候产生token,后用token等参数设计

安全接口验证,但实际过程中发现如果表单和非表单方式是有区别,因为非表单可以用

HttpServletRequest.getParameterNames获取post和get的请求参数(queryparam),如果使用

multi-part那就没办法使用上述方式,但可以用HttpServletRequest.getParts()。在使用这个方法处理

调试时候出现了如果下几个错误

1、Unable to process parts as no multi-part configuration

这个原因是因为web.xml没有配置multi-part配置,在serverlet节点里面

    <multipart-config>
        <max-file-size>52428800</max-file-size>
        <max-request-size>52428800</max-request-size>
        <file-size-threshold>0</file-size-threshold>
    </multipart-config> 

2、the request was rejected because no multipart boundary was found

这个原因是因为我用postman模拟请求时候加了header,这个地方不用手动加header的媒体类型

具体代码实现内容如下

@Provider  
public class VerifyFilter implements ContainerRequestFilter{

    @Context   
    private HttpServletRequest servletRequest;  
    @Context  
    private HttpServletResponse servletResponse;  
    
    private Logger filterLog=LoggerFactory.getLogger(VerifyFilter.class);
    
    private String substringBetween(String str, String open, String close) {
        if (str == null || open == null || close == null)
            return null;
        int start = str.indexOf(open);
        if (start != -1) {
            int end = str.indexOf(close, start + open.length());
            if (end != -1)
                return str.substring(start + open.length(), end);
        }
        return null;
    }
    
    @SuppressWarnings("rawtypes")
    private void ProcessMultiPart(ContainerRequestContext requestContext) throws IOException{
      /*HashMap<String,String> map=new HashMap<String, String>();
        HashMap<String,Object> resultMap=new HashMap<String,Object>();
        String signStr="";
        String timespan="0";
        String deviceid="";
        
        InputStream in = requestContext.getEntityStream();      
        int fileLen=1024;//URL参数部分长度
        byte[] fileContent = new byte[fileLen];
        String encoding = "UTF-8";
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int len;  
        while ((len = in.read(fileContent)) > -1 ) {              
            baos.write(fileContent, 0, len);  
        }  
        baos.flush();            
        InputStream stream1 = new ByteArrayInputStream(baos.toByteArray());         
        stream1.reset();
        requestContext.setEntityStream(stream1);
        
        InputStream stream2 = new ByteArrayInputStream(baos.toByteArray());  
              
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stream2));
        String lineStr = null;  
        int index;
        while((lineStr = bufferedReader.readLine()) != null){  
            //分析form-data
            lineStr=lineStr.trim();
            if(lineStr.contains("Content-Disposition")&&!lineStr.contains("filename")){
                index=lineStr.indexOf("name=");
                String name=lineStr.substring(index+6, lineStr.length());
                index=name.indexOf("\"");
                name=name.substring(0,name.length()-1);
                
                bufferedReader.readLine();//读取空格
                lineStr=bufferedReader.readLine();
                lineStr=URLDecoder.decode(lineStr,encoding).trim();
                //存入值
                if(name.equals("signStr")){
                    signStr=lineStr;        
                }
                else if(name.equals("timespan")){
                    timespan=lineStr;
                    map.put(name, lineStr);
                }
                else if(name.equals("deviceID")){
                    deviceid=lineStr;
                    map.put(name, lineStr);
                }           
                else{            
                    map.put(name, lineStr);                
                }        
            }          
        }           */   
       
        //in.close();  
        //bufferedReader.close();  
        //baos.close();
        //stream2.close();
        
       /* //是否有这三个参数
        String token= RedisService.getInstance().getAppImeiToken(deviceid);
        if(TextUtil.isNullEmptyOrWhitespace(token)){
            resultMap.put(RESULT, INVAILDEDTOKEN.getResultCode());
            Response response = Response.ok(resultMap).status(200).type(MediaType.APPLICATION_JSON).build();
            throw new WebApplicationException(response); // Throw new UnAuthorized   
        }
        map.put("token", token);
        long lCurTime=System.currentTimeMillis();
        long lTimeSpan=Long.parseLong(timespan);
        if(lCurTime-lTimeSpan>60000){
            filterLog.info(ErrorMessage.VERIFY_TIMESTAP,servletRequest.getRequestURI());
        }
        SortedMap<String,String> sort=new TreeMap<String,String>(map);
        Set es = sort.entrySet();
        Iterator it = es.iterator();
        StringBuilder sb=new StringBuilder();
          while(it.hasNext()){    
               Map.Entry entry = (Map.Entry)it.next();     
               sb.append(entry.getValue());                 
               //System.out.println("排序之后:"+entry.getKey()+"值:"+entry.getValue());    
          }  
        String okSignStr=MD5Util.getMd5String(sb.toString());
        if(!okSignStr.equals(signStr)){
            resultMap.put(RESULT, SIGNATUREINCONSISTENT.getResultCode());
            Response response = Response.ok(resultMap).status(200).type(MediaType.APPLICATION_JSON).build();
            throw new WebApplicationException(response); // Throw new UnAuthorized           
        }*/   
   
    }
    
    @SuppressWarnings("rawtypes")
       private void ProcessNoMultiPartPost(ContainerRequestContext requestContext) throws IOException{
        String signStr="";
        String timespan="0";
        String deviceid="";        
        HashMap<String,String> map=new HashMap<String, String>();
        String encoding = "UTF-8";  
        short fileLen=1024;//URL参数部分长度
        byte[] fileContent = new byte[fileLen];
     InputStream in = requestContext.getEntityStream();          
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int len;  
        while ((len = in.read(fileContent)) > -1 ) {  
            baos.write(fileContent, 0, len);  
        }  
        baos.flush();        
        InputStream stream1 = new ByteArrayInputStream(baos.toByteArray());  
        requestContext.setEntityStream(stream1);      
        String value=new String(baos.toByteArray(),encoding);        
        baos.close();
        String[] strArray = value.split("&");
        for(int i=0;i<strArray.length;++i){
            if(strArray[i].contains("Content-Type=")) continue;
            if(!strArray[i].contains("=")) continue;
            String[] strArray1=strArray[i].split("=");
            
            if(strArray1[0].equals("signStr")){
                signStr=strArray1[1];        
            }
            else if(strArray1[0].equals("timespan")){
                timespan=strArray1[1];
                map.put(strArray1[0], strArray1[1]);
            }
            else if(strArray1[0].equals("deviceID")){
                deviceid=strArray1[1];
                map.put(strArray1[0], strArray1[1]);
            }
            else{
                map.put(strArray1[0], strArray1[1]);
            }
        }
        
        //是否有这三个参数
          String token= RedisService.getInstance().getAppImeiToken(deviceid);
          if(TextUtil.isNullEmptyOrWhitespace(token)){
              HashMap<String,Object> resultMap=new HashMap<String,Object>();
              resultMap.put(RESULT, INVAILDEDTOKEN.getResultCode());
              Response response = Response.ok(resultMap).status(200).type(MediaType.APPLICATION_JSON).build();
              throw new WebApplicationException(response); // Throw new UnAuthorized   
          }
          map.put("token", token);
          long lCurTime=System.currentTimeMillis();
          long lTimeSpan=Long.parseLong(timespan);
          if(lCurTime-lTimeSpan>60000){
              filterLog.info(ErrorMessage.VERIFY_TIMESTAP,servletRequest.getRequestURI());
          }
          SortedMap<String,String> sort=new TreeMap<String,String>(map);
          Set es = sort.entrySet();
          Iterator it = es.iterator();
          StringBuilder sb=new StringBuilder();
          while(it.hasNext()){    
               Map.Entry entry = (Map.Entry)it.next();     
               sb.append(entry.getValue());                   
          }  
        System.out.println(sb.toString());  
        String okSignStr=MD5Util.getMd5String(sb.toString());
          if(!okSignStr.equals(signStr)){
              HashMap<String,Object> resultMap=new HashMap<String,Object>();
              resultMap.put(RESULT, SIGNATUREINCONSISTENT.getResultCode());
              Response response = Response.ok(resultMap).status(200).type(MediaType.APPLICATION_JSON).build();
              throw new WebApplicationException(response); // Throw new UnAuthorized           
          }    
    }
    
    @SuppressWarnings("rawtypes")
    private void ProcessNoMultiPart(ContainerRequestContext requestContext){
        Enumeration<String> listParam=servletRequest.getParameterNames();            
        HashMap<String,String> map=new HashMap<String, String>();
        String signStr="";
        String timespan="0";
        String deviceid="";
        //System.out.println(servletRequest.getRequestURI());
        if(!listParam.hasMoreElements()){
            HashMap<String,Object> resultMap=new HashMap<String,Object>();
            resultMap.put(RESULT, ARGUMENTSISNULLORNOTFIND.getResultCode());
            Response response = Response.ok(resultMap).status(200).type(MediaType.APPLICATION_JSON).build();
            throw new WebApplicationException(response); // Throw new UnAuthorized                   
        }
        while(listParam.hasMoreElements()){
            String name=(String)listParam.nextElement();
            String value=servletRequest.getParameter(name);
            if(name.equals("signStr")){
                signStr=value;        
            }
            else if(name.equals("timespan")){
                timespan=value;
                map.put(name, value);
            }
            else if(name.equals("deviceID")){
                deviceid=value;
                map.put(name, value);
            }
            else{
                map.put(name, value);
            }                
        }
        //是否有这三个参数
        String token= RedisService.getInstance().getAppImeiToken(deviceid);
        if(TextUtil.isNullEmptyOrWhitespace(token)){
            HashMap<String,Object> resultMap=new HashMap<String,Object>();
            resultMap.put(RESULT, INVAILDEDTOKEN.getResultCode());
            Response response = Response.ok(resultMap).status(200).type(MediaType.APPLICATION_JSON).build();
            throw new WebApplicationException(response); // Throw new UnAuthorized   
        }
        map.put("token", token);
        long lCurTime=System.currentTimeMillis();
        long lTimeSpan=Long.parseLong(timespan);
        if(lCurTime-lTimeSpan>60000){
            filterLog.info(ErrorMessage.VERIFY_TIMESTAP,servletRequest.getRequestURI());
        }
        SortedMap<String,String> sort=new TreeMap<String,String>(map);
        Set es = sort.entrySet();
        Iterator it = es.iterator();
        StringBuilder sb=new StringBuilder();
        while(it.hasNext()){    
             Map.Entry entry = (Map.Entry)it.next();     
             sb.append(entry.getValue());                 
             //System.out.println("排序之后:"+entry.getKey()+"值:"+entry.getValue());    
        }  
        String okSignStr=MD5Util.getMd5String(sb.toString());
        if(!okSignStr.equals(signStr)){
            HashMap<String,Object> resultMap=new HashMap<String,Object>();
            resultMap.put(RESULT, SIGNATUREINCONSISTENT.getResultCode());
            Response response = Response.ok(resultMap).status(200).type(MediaType.APPLICATION_JSON).build();
            throw new WebApplicationException(response); // Throw new UnAuthorized           
        }            
        
    }

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        // TODO Auto-generated method stub
        String url=servletRequest.getRequestURI();
        //媒体类型如果是mult/part-data        
        if(url.contains("/v1/api")){
            if(requestContext.getMethod().equals("GET")){
                ProcessNoMultiPart(requestContext);
            }
            else{
                MediaType mt=requestContext.getMediaType();
                if(mt==null||mt.getType()==null||mt.getSubtype()==null){
                    ProcessNoMultiPartPost(requestContext);
                }
                else if(MediaType.MULTIPART_FORM_DATA_TYPE.getType().equals(mt.getType())
                        &&MediaType.MULTIPART_FORM_DATA_TYPE.getSubtype().equals(mt.getSubtype())){
                    ProcessMultiPart(requestContext);
                }
                else{
                    ProcessNoMultiPartPost(requestContext);
                }
            }                        
        }        
    }

}

注意点,在传multi-part数据时候,如果用上述方法将导致数据流无法读取,因为业务层获取文件数据代码

如果这个写法

FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);

List<FileItem> items = upload.parseRequest(request);

查看源代码看到InputSream是用HttpServelRequest获取,而不是在jersey层的流,所以业务层不能读取

底层数据,要用jersey方式获取文件。但是会碰到一个注解错误,在web.xml里面添加就可以了。

<init-param>
    <param-name>jersey.config.server.provider.classnames</param-name>
    <param-value>org.glassfish.jersey.filter.LoggingFilter;org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>

</init-param>


业务demo参考

@POST
    @Path("/update")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public String update(@FormDataParam ("token") String deviceid,
            @FormDataParam("nickname") String nickName,
            @FormDataParam("sex") String sex,
            @FormDataParam("birthday") String birthday,
            @FormDataParam("file") InputStream saveFile,
            @FormDataParam("file") FormDataContentDisposition fileItem)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值