• Springboot后台参数拦截,解码或者接口拦截等


    一.使用场景:

    1.在前后端接口调用的过程中,某些接口数据是需要加密传输的 :比如密码等,前端编码后后端接口都必须需要解码,每个接口都解要做一次解码工作,这是一个很繁琐的事情

    2.如接口调用过程中,每次调用都需要传送一个token,我们怎样去对接口进行拦截

    所以本文就来讲一讲自己在工作中的全局解码的实现方式:

    前端编码的方式参考前一篇随笔:https://www.cnblogs.com/KdeS/p/12073331.html

     

     二.定义一个Filter或者OncePerRequestFilter

     OncePerRequestFilter:(在spring中,filter都默认继承OncePerRequestFilter)顾名思义,它能够确保在一次请求中只通过一次filter,而需要重复的执行。大家常识上都认为,一次请求本来就只filter一次,为什么还要由此特别限定呢,往往我们的常识和实际的实现并不真的一样,经过一番资料的查阅,此方法是为了兼容不同的web container,也就是说并不是所有的container都入我们期望的只过滤一次,servlet版本不同,执行过程也不同,因此,为了兼容各种不同运行环境和版本,默认filter继承OncePerRequestFilter是一个比较稳妥的选择。request.parameter中,但是我们都知道request.parameter中的数据只能进行读操作,不能进行写操作,怎么解决呢?

     这里会引入一个类 javax.servlet.http.HttpServletRequestWrapper,是一个扩展的通用接口,也就是会对request做一次包装,我们需要继承并重写这个方法。

    2.1 代码部分如下
    package com.grand.p1upgrade.filter;
    
    import java.util.HashMap;
    import java.util.Map;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    
    public class MyHttpServletRequestWrapper extends HttpServletRequestWrapper{
    
        // 用于存储请求参数
        private Map<String , String[]> params = new HashMap<String, String[]>(); 
             
        public MyHttpServletRequestWrapper(HttpServletRequest request) {
            super(request);
            // 把请求参数添加到我们自己的map当中
            this.params.putAll(request.getParameterMap());
        }
        public void setParameters(Map<String, Object> extraParams) {
            for (Map.Entry<String, Object> entry : extraParams.entrySet()) {
                setParameter(entry.getKey(), entry.getValue());
            }
        }
        /**
         * 添加参数到map中
         * @param name 
         * @param value
         */
        public void setParameter(String name, Object value) {
            if (value != null) {
                if (value instanceof String[]) {
                    params.put(name, (String[]) value);
                } else if (value instanceof String) {
                    params.put(name, new String[]{(String) value});
                } else {
                    params.put(name, new String[]{String.valueOf(value)});
                }
            }
        }
        
        /**
         * 重写getParameter,代表参数从当前类中的map获取
         * @param name
         * @return
         */
        @Override
        public String getParameter(String name) {
            String[]values = params.get(name);
            if(values == null || values.length == 0) {
                return null;
            }
            return values[0];
        }
    
        /**
         * 重写getParameterValues方法,从当前类的 map中取值
         * @param name
         * @return
         */
        @Override
        public String[] getParameterValues(String name) {
            return params.get(name);
        }
    }
     
    2.2 继承OncePerRequestFilter覆盖doFilterInternal对密码解码
    package com.grand.p1upgrade.filter;
    
    import java.io.IOException;
    import java.util.Base64;
    import javax.servlet.FilterChain;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import org.springframework.stereotype.Component;
    import org.springframework.web.filter.OncePerRequestFilter;
    
    /**
     * 参数过滤,对所有请求接口的请求进行拦截是否有pwd参数,有则解密,并将参数放入request.parameter中
     *
     * @author SanLi
     * Created by 2689170096@qq.com/SanLi on 2018/1/28
     */
    //@Component
    public class RequestParameterFilter extends OncePerRequestFilter {
    
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
                throws ServletException, IOException {
            String pwd=request.getParameter("pwd");
            if(pwd!=null) {
                pwd= new String(Base64.getDecoder().decode(pwd), "UTF-8");
                MyHttpServletRequestWrapper wrapper = new MyHttpServletRequestWrapper(request);
                wrapper.setParameter("pwd",pwd);
    /**
     * 1.一般filter都是一个链,web.xml 里面配置了几个就有几个。一个一个的连在一起
     *  request -> filter1 -> filter2 ->filter3 -> …. -> request resource.
     *
     * 2.chain.doFilter将请求转发给过滤器链下一个filter , 如果没有filter那就是你请求的资源
     */
                filterChain.doFilter(wrapper, response);
            }
            return;
        }
    
    }
    2.2 继承Filter对密码解码
    package com.grand.p1upgrade.filter;
    
    import java.io.IOException;
    import java.util.Base64;
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import org.apache.commons.lang.StringUtils;
    import org.springframework.stereotype.Component;
    import lombok.extern.java.Log;
    
    /**
     * 过滤所有的请求,包含静态资源,如果请求cookie中含有token或请求为静态资源,则放行请求,否则进入到登陆页面
     */
    @Log
    @Component
    public class TokenFilter implements Filter{
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {}
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
                FilterChain chain) throws IOException, ServletException {
            MyHttpServletRequestWrapper wrapper = null;
            String token = null;
            HttpServletRequest request= (HttpServletRequest) servletRequest;
            HttpServletResponse response = (HttpServletResponse) servletResponse;
            String uri = request.getRequestURI();
           //参数过滤,对所有请求接口的请求进行拦截是否有pwd参数,有则解密,并将参数放入request.parameter中
            String pwd=request.getParameter("pwd");        
            wrapper = new MyHttpServletRequestWrapper(request);
            if(pwd!=null) {
                pwd= new String(Base64.getDecoder().decode(pwd), "UTF-8");
                wrapper.setParameter("pwd",pwd);
            }
          
            if(uri.contains("/login"))||uri.contains("/static")){
               //通过,不拦截
                chain.doFilter(wrapper,response);
            }else{
                // 拦截请求,判断cookie中是否有token,没有则跳转到登陆页,有则放行
                Cookie[] cookies = request.getCookies();
                if(cookies!=null){
                    for (Cookie cookie : cookies) {
                        if("token".equals(cookie.getName())){
                            // 前端传递过来的token包含两部分:key,value
                            token = cookie.getValue();
                        }
    
                    }
                }
                // token有值,且包含"_",就通过
                if(StringUtils.isNotEmpty(token)&&token.contains("_")){
                    chain.doFilter(wrapper,response);
                }else{
                    response.setStatus(401); // 需要权限
                }
            }
        }
    
        @Override
        public void destroy() {}
    
    }

    总结:

    在我使用的过程中继承OncePerRequestFilter或者是继承Filter同样都能达到我们想要的效果。
  • 相关阅读:
    安全相关小知识
    http小知识
    跨域资源共享 CORS
    Django——CRSF攻击及处理
    Django——XSS攻击及处理
    Django——模版层(前后端交互编码方式,django模板使用的两种方式,模板语法之变量&深度查询句点符,模板渲染成标签还是原字符串,过滤器+自定义,标签+自定义)
    Django——Postman介绍及安装, 测试项目
    Django——视图层(请求&响应对象,cbv和fbv,文件上传)
    一个http请求从浏览器发出去,经历的过程(即上网流程)
    Django——有名分组 无名分组,反向解析,名称空间
  • 原文地址:https://www.cnblogs.com/KdeS/p/12101672.html
Copyright © 2020-2023  润新知