防止重复提交是一种常见的安全措施,用于防止用户在短时间内多次提交相同的请求。通过使用注解,我们可以在代码层面实现这种防护机制,以提高系统的安全性和稳定性。
防止重复提交的机制在许多Web应用程序中都是必需的,特别是在涉及到敏感操作或需要保证数据一致性的情况下。以下是一些常见的场景:
除了使用注解,还有其他一些方式可以实现防止重复提交的机制,例如:
下面是使用注解实现防止重复提交的一般步骤:
/**
* 验证是否重复提交
* @param request
* @return
* @throws Exception
*/
️public ️abstract ️boolean ️isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation);
定义一个实现类,继承拦截器这个类,实现其方法具体的验证方法也在其中
类中的具体方法如下
️@Override
️public ️boolean ️isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation)
{
String nowParams = "";
️if (request ️instanceof RepeatedlyRequestWrapper)
{
RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
nowParams = HttpHelper.getBodyString(repeatedlyRequest);
}
// body参数为空,获取Parameter的数据
️if (StringUtils.isEmpty(nowParams))
{
nowParams = JSONObject.toJSONString(request.getParameterMap());
}
Map<String, Object> nowDataMap = ️new HashMap<String, Object>();
nowDataMap.put(REPEAT_PARAMS, nowParams);
nowDataMap.put(REPEAT_TIME, System.currentTimeMillis());
// 请求地址(作为存放cache的key值)
String url = request.getRequestURI();
// 唯一值(没有消息头则使用请求地址)
String submitKey = StringUtils.trimToEmpty(request.getHeader(header));
// 唯一标识(指定key + url + 消息头)
String cacheRepeatKey = Constants.REPEAT_SUBMIT_KEY + url + submitKey;
Object sessionObj = redisCache.getCacheObject(cacheRepeatKey);
️if (sessionObj != ️null)
{
Map<String, Object> sessionMap = (Map<String, Object>) sessionObj;
️if (sessionMap.containsKey(url))
{
Map<String, Object> preDataMap = (Map<String, Object>) sessionMap.get(url);
️if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap, annotation.interval()))
{
️return ️true;
}
}
}
Map<String, Object> cacheMap = ️new HashMap<String, Object>();
cacheMap.put(url, nowDataMap);
redisCache.setCacheObject(cacheRepeatKey, cacheMap, annotation.interval(), TimeUnit.MILLISECONDS);
️return ️false;
}
其中compareParams是判断参数是否相同方法,compareTime判断两次间隔时间
️@RestController
️public ️class ️TestController {
️@RepeatSubmit
️@PostMapping("/test")
️public ️void ️test(@RequestBody User user) {
// 处理逻辑
}
}
在上述示例中,我们定义了一个AvoidDuplicateSubmit注解,并在UserController的createUser方法上使用了该注解。然后,我们通过AvoidDuplicateSubmitAspect切面类,在方法执行前进行重复提交检查。
总结通过使用注解,我们可以在代码层面实现防止重复提交的机制。通过定义自定义注解、实现拦截器或切面以及在需要进行重复提交检查的方法上使用注解,我们可以有效地防止用户在短时间内多次提交相同的请求,提高系统的安全性和稳定性。