持续创作,加速成长!这是我参与「掘金日新计划 · 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方法对数据源进行各种校验和处理。框架原理图如下:
2:框架功能
a、参数校验类:防SQL注入、参数校验等
b、鉴权类:操作鉴权、licence鉴权等
c、业务类:文件格式、大小校验等
d、对request进行数据转换处理:归一化处理等
3:可扩展性
a、新增接口,只需一个注解
b、新增业务,只需增加一个校验器
c、良好的设计模式使得业务内部的扩展也极为方便
d、框架除了支持各种校验外,还支持对参数进行转换
三、小结
良好的设计使得本框架拥用强大的横向和纵向扩展能力,代码简洁优雅,层次感分明,十分方便维护。