上一篇 <<<安全技术--Https相关知识
下一篇 >>>安全框架--SpringSecurity
幂等:无论请求多少次,数据都不会变,防止重复提交
幂等设计方案
- 1.MVCC方案(乐观锁方式)
select * from tablename where condition=#condition# // 取出要跟新的对象,带有版本 versoin
update tableName set name=#name#,version=version+1 where version=#version#
在更新的过程中利用 version 来防止,其他操作对对象的并发更新,导致更新丢失。为了避免失败,通常需要一定的重试机制。
- 2.悲观锁
select for update,整个执行过程中锁定该订单对应的记录。注意:这种在DB读大于写的情况下尽量少用。
- 3.去重表
在插入数据的时候,插入去重表,利用数据库的唯一索引特性,保证唯一的逻辑。
- 4.Token机制
业务要求:页面的数据只能被点击提交一次
发生原因:由于重复点击或者网络重发,或者 nginx 重发等情况会导致数据被重复提交
解决办法:
集群环境:采用token加redis(redis 单线程的,处理需要排队)
单JVM环境:采用token加redis或token加jvm内存
处理流程:
--数据提交前要向服务的申请token,token放到redis或jvm内存,token有有效时间
--提交后后台校验token,同时删除token
token特点:要申请,一次有效性,可以限流
纯手写互联网API接口幂等框架
- 接口方式保证幂等性
a、提供查询令牌查询接口
b、令牌放在请求头中提交,服务端使用AOP统一处理
- 表单提交保证幂等性
a、自定义注解ExtApiToken,AOP中发现此注解就生成令牌信息放到request中,页面上做令牌的隐藏
b、-令牌信息和其他数据一起以form方式提交到服务端,服务端以ExtApiIdempotent注解来做AOP统一处理
- 3.核心代码
// 1.使用AOP环绕通知拦截所有访问(controller)
@Pointcut("execution(public * com.jarye.controller.*.*(..))")
public void rlAop() {}
// 含有ExtApiToken注解的均设置令牌信息
@Before("rlAop()")
public void before(JoinPoint point) {
MethodSignature signature = (MethodSignature) point.getSignature();
ExtApiToken extApiToken = signature.getMethod().getDeclaredAnnotation(ExtApiToken.class);
if (null==extApiToken) {
return;
}
// 可以放入到AOP代码 前置通知
getRequest().setAttribute("token", redisToken.getToken());
}
// 环绕通知
@Around("rlAop()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
// 2.判断方法上是否有加ExtApiIdempotent注解
MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
ExtApiIdempotent declaredAnnotation = methodSignature.getMethod().getDeclaredAnnotation(ExtApiIdempotent.class);
// 3.如何方法上有加上ExtApiIdempotent
if (declaredAnnotation != null) {
String type = declaredAnnotation.type();
// 如何使用Token 解决幂等性
String token = null;
HttpServletRequest request = getRequest();
//接口形式是放在头部,表单形式是放在body中
if (type.equals(ConstantUtils.EXTAPIHEAD)) {
token = request.getHeader("token");
} else {
token = request.getParameter("token");
}
if (StringUtils.isEmpty(token)) {
return "参数错误";
}
// 3.接口获取对应的令牌,如果能够获取该(从redis获取令牌)令牌(将当前令牌删除掉) 就直接执行该访问的业务逻辑
boolean isToken = redisToken.findToken(token);
// 4.接口获取对应的令牌,如果获取不到该令牌 直接返回请勿重复提交
if (!isToken) {
response("请勿重复提交!");
// 后面方法不在继续执行
return null;
}
}
// 放行
Object proceed = proceedingJoinPoint.proceed();
return proceed;
}
相关文章链接:
<<<Web常用攻击手段-XSS
<<<Web常用攻击手段-SQL注入
<<<Web常用攻击手段-Http请求防盗链
<<<Web常用攻击手段-CSRF攻击
<<<Web常用攻击手段-上传文件漏洞
<<<Web常用攻击手段-忘记密码
<<<Web常用攻击手段-其他漏洞
<<<安全技术--数据加密/认证技术
<<<安全技术--Https相关知识
<<<安全框架--SpringSecurity
<<<安全框架--JWT
<<<安全框架--OAuth2
<<<安全架构整体设计方案
网友评论