首页 > 编程语言 > SpringBoot 拦截器和自定义注解判断请求是否合法
2020
12-29

SpringBoot 拦截器和自定义注解判断请求是否合法

应用场景举例:

当不同身份的用户请求一个接口时,用来校验用户某些身份,这样可以对单个字段数据进行精确权限控制,具体看代码注释

自定义注解

/**
 * 对比请求的用户身份是否符合
 * @author liuyalong
 * @date 2020/9/25 16:03
 */
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface CompareUser {
  /**
   * The name of the request parameter to bind .
   */
  @AliasFor("name") String value() default "";
  @AliasFor("value") String name() default "";
}

给controller的字段添加注解

  @ApiOperation(value = "删除用户", notes = "根据手机号来删除用户")
  @PostMapping(value = "/delete_phone")
  public BaseCommonResult<Integer> deletePhone(@CompareUser(value = "phone") String phone) {
    int i = userService.deleteByPhone(phone);
    return BaseCommonResult.success(i);
  }

参数解析器

记得继承后加@Component,这里是Base...所以不用

/**
 * @author liuyalong
 * @date 2020/9/25 15:56
 */
public class BaseCurrentUserInterceptor implements HandlerMethodArgumentResolver {
  /**
   * 用于判定是否需要处理该参数注解,返回true为需要,
   * 并会去调用下面的方法resolveArgument。
   */
  @Override
  public boolean supportsParameter(MethodParameter parameter) {
    //只处理CurrentUser注解修饰的参数
    return parameter.hasParameterAnnotation(CompareUser.class);
  }

  /**
   * 对比用户信息
   */
  @Override
  public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
    CompareUser parameterAnnotation = parameter.getParameterAnnotation(CompareUser.class);

    Class<?> parameterType = parameter.getParameterType();
    if (parameterAnnotation == null) {
      throw new IllegalArgumentException("Unknown parameter type [" + parameterType.getName() + "]");
    }

    /*
     * 获取要验证的字段名
     */

    //检查是否给字段取了别名
    String paramName = "".equalsIgnoreCase(parameterAnnotation.name()) ? parameterAnnotation.value() : parameterAnnotation.name();
    if ("".equalsIgnoreCase(parameterAnnotation.name())) {
      //从参数中获取定义的字段名
      paramName = parameter.getParameter().getName();
    }

    //获取请求字段的值
    String paramValue = String.valueOf(webRequest.getParameter(paramName));

    //从请求头中获取已经登录的用户
    String userName = webRequest.getHeader(AuthConstant.USER_TOKEN_HEADER);

    //对于root用户,可以操作一切,所以直接返回
    if (!AuthConstant.ROOT_USER.equals(userName)) {
      //判断身份是否一致,不一致就抛出异常,让RestControllerAdvice处理
      if (userName == null || !userName.equals(paramValue)) {
        throw new NotSameAuthorException();
      }
    }
    //将参数原封不动返回出去,需要还原回需要的类型
    WebDataBinder binder = binderFactory.createBinder(webRequest, parameterType, paramName);
    return binder.convertIfNecessary(paramValue, parameterType, parameter);
  }
}

配置WebMvcConfigurer

注意这里提供了两种方式加载,因为

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
  @Autowired
  private HandlerInterceptor handlerInterceptor;

  @Autowired
  private HandlerMethodArgumentResolver currentUserInterceptor;

  @Autowired
  private RequestMappingHandlerAdapter requestMappingHandlerAdapter;

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(handlerInterceptor).addPathPatterns("/**");
  }

  //参数解析器,自定义的优先级最低,所以会失效,
  // 解决方案是下面的 @PostConstruct ,把优先级调最高
  // 但是这样@PathParam @RequestParam就失效了,@CompareUser(value="xxx")可以完全替换@RequestParam功能
//  @Override
//  public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
//    resolvers.add(currentUserInterceptor);
//
//  }

  /**
   *参数解析器优先级调最高
   */
  @PostConstruct
  public void init() {
    // 获取当前 RequestMappingHandlerAdapter 所有的 Resolver 对象
    List<HandlerMethodArgumentResolver> resolvers = requestMappingHandlerAdapter.getArgumentResolvers();
    List<HandlerMethodArgumentResolver> newResolvers = new ArrayList<>(resolvers.size() + 1);

    // 添加自定义参数解析器到集合首位
    newResolvers.add(currentUserInterceptor);

    // 添加 已注册的 Resolver 对象集合
    newResolvers.addAll(resolvers);
    // 重新设置 Resolver 对象集合
    requestMappingHandlerAdapter.setArgumentResolvers(newResolvers);
  }
}

效果

只有特定身份人员才可以删除操作

以上就是SpringBoot 拦截器和自定义注解判断请求是否合法的详细内容,更多关于SpringBoot 拦截器和自定义注解的资料请关注自学编程网其它相关文章!

编程技巧