【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