【Spring】自定义argumentResolver参数解析器 解决用户ID问题

【Spring】自定义argumentResolver参数解析器 解决用户ID问题

项目环境:Spring + Spring MVC + Spring Security + 其他

 

最近开发系统的过程中,有一些控制器方法会要求客户端传入userID值。

一开始在JS中获取LocalStorage里存的userId提交,存在被伪造请求的可能。

由于框架使用的是Spring Security,可以通过Principal直接获取用户信息,所以考虑到安全性,不由用户携带用户ID提交请求,而是转为服务器主动获取用户ID。

SecurityContext sc = SecurityContextHolder.getContext();
Authentication auth = sc.getAuthentication();
LoginUser loginUser = (LoginUser) auth.getPrincipal();
Integer userId = loginUser.getId();

 

但每次都在控制器里加这一段,控制器数量一多后,代码变得不简洁,所以思考能否使用Spring注解来解决。

 

在网上查询资料后,Spring MVC 可以通过注解往函数里添加额外的信息,使得这些被添加注解的数据可以交由框架来处理并赋值。

 

第一步,添加自定义注解,注解名为UserId

/**
 * @author qinyuguan
 */
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UserId {
    boolean required() default true;
}

 

第二步,写UserId的参数解析器

/**
 * @author qinyuguan
 * @date 2020/3/15 17:21
 */
public class UserIdMethodArgumentResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        if (parameter.getParameterType().equals(Integer.class) && parameter.hasParameterAnnotation(UserId.class)) {
            return true;
        }
        return false;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        UserId currentUserAnnotation = parameter.getParameterAnnotation(UserId.class);

        SecurityContext sc = SecurityContextHolder.getContext();
        Authentication auth = sc.getAuthentication();
        LoginUser loginUser = (LoginUser) auth.getPrincipal();
        Integer userId = loginUser.getId();
        return userId;
    }
}

 

第三步,注册解析器,配置MvcConfig

/**
 * @author qinyuguan
 * @date 2020/3/15 17:27
 */
@Configuration
public class WebAppConfig{

    @Bean
    public WebMvcConfigurer webMvcConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
                argumentResolvers.add(new UserIdMethodArgumentResolver());
            }
        };
    }
}

 

最后,使用,在控制器里随便写一个方法,在参数里添加一个Id的参数,并为其添加@UserId注解:

 

    @GetMapping("/main")
    @ResponseBody
    public Results getInfo(@UserId Integer userId){
        System.out.println(userId);
        return service.getInfo(userId);
    }

 

测试,是否可用,控制台输出了用户ID。

1001

 

posted @ 2020-03-15 17:51  秦羽纶  阅读(1162)  评论(0编辑  收藏  举报