使用环绕增强注解解决防重复提交及防重放安全问题
AvoidRepeatableCommit 注释类
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AvoidRepeatableCommit {
}
AvoidRepeatableCommitAspect 环绕类
CacheStore 是hutool的缓存可以换成redis,SHA256也是使用hutool的内置加密方法
import java.util.Date;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import cn.com.sgcc.sgec.ksplatform.common.exception.KsException;
import cn.com.sgcc.sgec.ksplatform.security.util.CacheStore;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestAlgorithm;
import cn.hutool.crypto.digest.Digester;
import lombok.extern.slf4j.Slf4j;
/**
* 防重复提交
* @author Mr.Xiao
*
*/
@Aspect
@Component
@Slf4j
public class AvoidRepeatableCommitAspect {
@Autowired
CacheStore cacheStore;
/**
* @param point
* @throws Throwable
*/
@Around("@annotation(cn.com.aop.AvoidRepeatableCommit)")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
//防重放规则1.0 (url防重放)
String tid = "";
Cookie[] cookie = request.getCookies();
if(null != cookie) {
for(Cookie c : cookie) {
if(c.getName().equals("token")) {
tid = c.getValue();
break;
}
}
}
String key = tid + "-" + request.getRequestURI();
String value = cacheStore.getTokenUrlCache().get(key);
if(StrUtil.isNotEmpty(value)) {
log.error("频繁操作{}",key);
throw new KsException("请勿频繁操作");
}else {
cacheStore.getTokenUrlCache().put(key, "1",DateUnit.SECOND.getMillis()*3);
}
//防重放规则2.0 (数据包防重放)
String timestamp = request.getHeader("timestamp");
String nonce = request.getHeader("nonce");
String sign = request.getHeader("sign");
if(StrUtil.hasBlank(timestamp,nonce,sign)) {
log.error("参数不完整{}",nonce);
throw new KsException("参数不完整");
}
//大于10分钟的数据包失效不可用
long bmin = DateUtil.between(new Date(), new Date(Long.parseLong(timestamp)), DateUnit.MINUTE);
if(bmin > 10) {
log.error("数据包已失效{}",nonce);
throw new KsException("数据包已失效");
}
Digester sha256 = new Digester(DigestAlgorithm.SHA256);
String sign1 = sha256.digestHex(sha256.digestHex(nonce)+timestamp);
//规则校验
if(!sign.equals(sign1)) {
log.error("篡改数据包非法提交{}",nonce);
throw new KsException("篡改数据包非法提交");
}
value = cacheStore.getNonceCache().get(timestamp+nonce);
if(StrUtil.isNotEmpty(value)) {
log.error("重复提交{}",nonce);
throw new KsException("重复提交");
}
Object o = pjp.proceed();
cacheStore.getNonceCache().put(timestamp+nonce, "1",DateUnit.MINUTE.getMillis()*11);
return o;
}
}
注解的使用
@PostMapping("operationAudit")
@ApiOperation(value = "运营审核")
@Secured(RolesConstant.AUDITOR) //审核员才有权限操作
@AvoidRepeatableCommit // todo
public ItemResponse operationAudit(OnlineMeasureAuditDTO auditDTO) throws Exception {
OnlineMeasure onlineMeasure = onlineMeasureService.getById(auditDTO.getId());
if (onlineMeasure == null){
return ItemResponse.fault("数据错误");
}
/**
* 待审核 10 光伏云 驳回 30 运营才能审核
*/
if ( ( !OnlineMeasureConstant.AUDIT_10.equals(onlineMeasure.getStatus())
&& !OnlineMeasureConstant.AUDIT_30.equals(onlineMeasure.getStatus()) ) ){
return ItemResponse.fault("审核状态错误");
}
ItemResponse result = auditRecordService.onlineMeasureOperationAudit(auditDTO);
return result;
}


2540

被折叠的 条评论
为什么被折叠?



