开发了个小框架,对restful接口的动态拦截

174 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第8天,点击查看活动详情

一、背景

web应用开发,面临着诸多挑战,安全防护尤为重要。安全防护意识必须深入每一位开发员工的灵魂,不能投机取巧。安全问题很多,比如对数据源进行验证:校验其字段类型、数据范围、格式是否合法等;对用户进行鉴权:是否有操作权限,是否拥有licence权限等;对输入的数据源做防止缓冲区溢出校验:上传文件格式是非合法、文件大小是否合适、访问的资源是否因为过大造成微服务内存溢出、磁盘撑爆等;有时还需要对请求参数进行修改转。针对上述现状,本文基于AOP,通过动态拦截技术,实现对restful接口的防护框架。

二、框架介绍

1:原理

本框架采用DynamicFeature实现AOP。通过注解的方式对restful接口进行拦截防护。本框架实现拦截的的步骤如下:

a、实现DynamicFeature接口,把filter注册到上下文

@Provider
public class RequestFeature implements DynamicFeature{
 
    @Override
    public void configure(ResourceInfo resourceInfo, FeatureContext context) {
        RequestValidator validator = resourceInfo.getResourceMethod().getAnnotation(RequestValidator.class);
        if(validator != null) {
            RequestFilter requestFilter = HK2Utils.getService(RequestFilter.class);
            requestFilter.setValidatorType(validator);
            context.register(requestFilter);
        }
    }
}

b、实现ContainerRequestFilter接口,将应用逻辑写在实现接口的filter方法中

@Service
@PerLookup
@PreMatching
@Slf4j
public class RequestFilter implements ContainerRequestFilter{
    @Override
    public void filter(ContainerRequestContext requestContext){
        try {
            auth(requestContext);
            validParameter(requestContext);
        }catch (IOException e){
            log.warn("parameter invalid or valid fail", e);
            throw Validator.buildWebException(ResultCode.NBI_PARAMETERS_INVALID_EXCEPTION);
        }
    }
}

c、定义接口和参数注解,通过枚举值决定做什么校验

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequestValidator {
 
    enum ValidatorType{
        VALID_PARAMETER{
            @Override
            public String getType() {
                return "parameter";
            }
        },
        VALID_SQL{
            @Override
            public String getType() {
                return "sql";
            }
        },
        AUTH_LICENCE{
            @Override
            public String getType() {
                return "licence";
            }
        },
        AUTH_MAINTAIN{
            @Override
            public String getType() {
                return "operation.naf.maintain";
            }
        },
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequestParameter {
    String OPEN = "openInterface";
    String UPDATE = "updateInterface";
    String QUERY = "queryInterface";
    String DELETE = "deleteInterface";
    String UPLOAD = "uploadFile";
    String DEPLOY_INFO = "queryDeployInfo";
 
 
    @RequiredArgsConstructor
    @Getter
    enum Resource {
        OPEN_INTERFACE(OPEN),
        UPDATE_INTERFACE(UPDATE),
        QUERY_INTERFACE(QUERY),
        DELETE_INTERFACE(DELETE),
        UPLOAD_FILE(UPLOAD),
        QUERY_DEPLOY(DEPLOY_INFO);
        private final String realValue;
    }
 
    Resource resource() default Resource.QUERY_INTERFACE;
}

d、将DynamicFeature注册到jersey的环境变量中

FeatureRegister {
    Environment (){
        .jersey().register(RequestFeature.)}
}

e、在restful接口上添加注解声明

@Service
public class FeatureRegister {
    @Inject
    private Environment environment;
 
    @PostConstruct
    public void init(){
        environment.jersey().register(RequestFeature.class);
    }
}

f、定义配置文件

配置文件定义了各个参数的范围、类型、是否要进行数据转化、其余业务校验【比如文件格式大小等】

},
"uploadFile": {
"bodyAttrList": [{
   "pos": "filename",
   "type": "String",
   "range": "128"
}],
"businessAttrList": [{
   "pos": "name",
   "type": "name",
   "range": "file"
},
   {
      "pos": "filename",
      "type": "filename",
      "range": ".zip"
   },
   {
      "pos": "fileSize",
      "type": "fileSize",
      "range": "100"
   }]
   },
"updateInterface": {
   "urlAttrList": [{
      "pos": "id",
      "type": "Long",
      "range": "[0-4294967295]"
   }],
   "bodyAttrList": [{
      "pos": "cron",
      "type": "String",
      "range": "2048",
      "normalize": "true"
   }],

当restful接口请求过来时,加上注解的接口会被拦截,执行过滤器的filter方法。应用可在filter方法对数据源进行各种校验和处理。框架原理图如下:

image.png

2:框架功能

a、参数校验类:防SQL注入、参数校验等

b、鉴权类:操作鉴权、licence鉴权等

c、业务类:文件格式、大小校验等

d、对request进行数据转换处理:归一化处理等

3:可扩展性

a、新增接口,只需一个注解

b、新增业务,只需增加一个校验器

c、良好的设计模式使得业务内部的扩展也极为方便

d、框架除了支持各种校验外,还支持对参数进行转换

三、小结

良好的设计使得本框架拥用强大的横向和纵向扩展能力,代码简洁优雅,层次感分明,十分方便维护。