先说一下问题,在appScan扫描出了几个API成批分批的安全问题。
这个问题的原因就是参数和后端定义的实体类的参数不同,前端参数应该是后端参数子集的一个关系。想了很多方法,既然参数问题,那我可以AOP直接拦截前端参数,然后跟后端进行对比,如果前端传过来的参数是后端定义不存在的,直接抛异常。
项目是springboot 项目,直接在common模块下面建一个aop包写切面类:
@Aspect
@Component
public class MastAspect {
// @Pointcut("execution(* com.meehealth.emss.module.mast.controller..*.*(..))")
@Pointcut("@annotation(com.meehealth.emss.framework.common.aop.InterfaceMate)")
public void e() {
}
@Around("e()")
public Object around(ProceedingJoinPoint point) throws Throwable {
// 获取目标方法的入参
Object[] args = point.getArgs();
// 实体类json
Object obj1 = args[0];
// 获取被注解方法上的注解
MethodSignature methodSignature = (MethodSignature) point.getSignature();
InterfaceMate specialRequestAnnotation = methodSignature.getMethod().getAnnotation(InterfaceMate.class);
// 获取注解中的值
String value1 = specialRequestAnnotation.value();
// 创建Gson对象
Gson gson = new Gson();
// 将Java对象(obj1)转换为JsonObject对象(jsonObject1)
JsonObject jsonObject1 = new JsonObject();
Class<?> clazz = obj1.getClass();
while (clazz != null) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
Object value = field.get(obj1);
// 检查字段名是否为需要排除的字段
if(value1.equals("login")){
if (field.getName().equals("tenantName") || field.getName().equals("rememberMe")) {
continue; // 跳过该字段
}}
jsonObject1.addProperty(field.getName(), gson.toJson(value));
}
clazz = clazz.getSuperclass();
}
// 从JoinPoint中获取Servlet请求
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
if(request==null){
Object result = point.proceed();
return result;
}
BufferedReader reader = request.getReader();
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
String requestData = sb.toString();
org.json.JSONObject jsonObject2 = new org.json.JSONObject(requestData);
// 排除特定字段
if (value1.equals("login")) {
Iterator<String> keys = jsonObject2.keys();
while (keys.hasNext()) {
String key = keys.next();
// 检查字段名是否为需要排除的字段
if (key.equals("tenantName") || key.equals("rememberMe")) {
keys.remove(); // 移除该字段
}
}
}
boolean isEqual = compare(String.valueOf(jsonObject1), String.valueOf(jsonObject2));
if (isEqual == false) {
throw exception(UNKNOWN_ATTRIBUTE_EXIST);
}
Object result = point.proceed();
return result;
}
//Josn对比
public static boolean compare(String json1, String json2) throws IOException {
ObjectMapper mapper = new ObjectMapper();
TypeReference<LinkedHashMap<String, Object>> typeRef =
new TypeReference<LinkedHashMap<String, Object>>() {};
LinkedHashMap<String, Object> map1 = mapper.readValue(json1, typeRef);
LinkedHashMap<String, Object> map2 = mapper.readValue(json2, typeRef);
return map1.keySet().containsAll(map2.keySet());
}
}
项目启动后发现AOP并没有生效。
在翻阅了相关资料后发现国内还搜不到 ,是我搜索问题方法有问题?不过最后还是在stackoverflow找到了, 如果AOP如果跨模块需要加一个配置类。
项目结构:
parent-project //项目名称
----common[Aop.class ,Config.class] //aop切面
----controller[请求] //请求路径
----service[Application] //启动类
Config.class 配置类
@Configuration
@ComponentScan("com.meehealth.emss.framework.common.aop")
public class Config {
@Bean
public MastAspect createAop() {
return new MastAspect();
}
}
在启动类上引入一下
@Import(Config.class) //启动加主键,引入配置文件
然后AOP就可以使用了。