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);
    }
}

效果

只有特定身份人員才可以刪除操作


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM