天天看点

spring boot之动态添加和修改请求参数,并实现token认证

  在实际开发的时候,当前端参数传输传递并解析的过程中也许会做许多重复的工作,例如:使用token进行登录认证的时候,每一次token传到服务端之后都要在service中手动进行一次转化,变成实际的uid。

  要解决这个问题,就需要对spring boot的RequestMapping方法参数赋值的过程进行调试,当方法中的参数为基本类型或者包装类型的时候,调试的请求如下。

@GetMapping("/param")
    public Object param(String uid,String name){
        return uid;
    }           

  通过调试可以发现,参数赋值发生在RequestParamMethodArgumentResolver.resolveName()方法中,该方法通过RequestMapping中方法的参数名调用request.getParameterValues(name)以获取请求的值,从而进行参数的赋值。

  还有另外一种情况,就是当RequestMapping方法参数为pojo对象时,spring处理会不一样。

@GetMapping("/bean")
    private Object gets(User user){
        return user;
    }
    public class User {
        private String uid;
        private String name;
    }           

  通过调试可以发现,在RequestMapping中参数为POJO类型的时候,参数赋值发生在WebUtils.getParametersStartingWith()方法中,这里会通过request.getParameterNames()方法获取所有传递过来的参数并遍历它。在遍历的过程中,会根据遍历的item去匹配pojo的参数并通过request.getParameterValues(paramName)进行赋值。

  如上就是spring对RequestMapper的参数赋值的原理了,主要是通过request.getParameterValues(paramName)进行参数值的获取实现的。再次梳理一下需求,当客户端传递了一个token到服务端之后,服务端需要对token进行认证,然后得到uid并映射到RequestMapper对应的方法中参数uid,或者pojo中的uid属性中。

  通过源码分析并结合需求,解决思路如下:

  使用TokenRequestWrapper包装类对ServletRequest中的getParameterValues和getParameterNames方法进行重写

public class TokenRequestWrapper extends HttpServletRequestWrapper {
    TokenRequestWrapper(HttpServletRequest request) {
        super(request);
    }
    /**
     * 修改此方法主要是因为当RequestMapper中的参数为pojo类型时,
     * 会通过此方法获取所有的请求参数并进行遍历,对pojo属性赋值
     * @return
     */
    @Override
    public Enumeration<String> getParameterNames() {
        Enumeration<String> enumeration = super.getParameterNames();
        ArrayList<String> list = Collections.list(enumeration);
        //当有token字段时动态的添加uid字段
        if (list.contains("token")){
            list.add("uid");
            return Collections.enumeration(list);
        }else {
            return super.getParameterNames();
        }
    }
    @Override
    public String[] getParameterValues(String name) {
        if ("uid".equals(name)){
            return new String[]{TokenUtil.verifyToken(getParameter("token"))};
        }
        return super.getParameterValues(name);
    }
}           

  新建一个filter并添加到filter调用链中,通过chain.doFilter把对ServletRequest包装过后的TokenRequestWrapper传递给spring进行处理。

@Component
public class TokenFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        chain.doFilter(new TokenRequestWrapper((HttpServletRequest) req), res);
    }
}           

测试

接口:/param?token=213&name=231

spring boot之动态添加和修改请求参数,并实现token认证

接口:/bean?token=213&name=231

spring boot之动态添加和修改请求参数,并实现token认证

继续阅读