执行:
1. [存储] 申请密钥(时间戳a)。
2. [网站] 如果帖子锁定/未知状态?则拒绝,如果有c且a<=c则拒绝,否则记录未知状态和时间戳a,返回执行密钥(a+5)。
3. [存储] 如果时间>a+5则拒绝,否则执行操作后回调此时时间戳b。
4. [网站] 若不是未知状态(没有a)或b<=a则拒绝,否则保存已知状态并记录c=(a+5或b中最大值)。
5. [循环] 新一轮a<=c拒绝,未知状态拒绝。
疑点:
时间>a+5时又申请了同样的新操作,而首次b=a+30时执行完毕并回调了状态?
因此未知状态的内容应该拒绝新的执行密钥申请!即未知状态是一次性的,执行后直到核销再也不可以进行除首次外的其他状态修改了!
示例:
用户希望上传文件,向存储端申请上传询问(tid),存储端批准并回调查询密钥md5(tid/time_a)
使用返回的查询密钥对网站进行请求,根据tid验证权限,写入未知状态,返回执行密钥md5(tid/time_a+5)
存储端确认time_a+5未过期,执行上传操作,成功后返回密钥md5(tid/time_b)
网站确认有time_a且time_b>time_a,则修改未知状态为已上传,记录max(time_b,time_a+5)
即便前几步重复执行多次也没关系,时间戳均可确保下一次操作与本次操作至少间隔5秒。
防范:(奉行“防用户如防贼”,被搞怕了……)
1. 用户短时期申请2个密钥,先进行后一个操作,然后再进行前一个操作?(例如使文件上传后不记录?)
不可能。新密钥一定>a+5,此时前一个执行密钥已无法操作。
2. 用户使用第3步生成的时间戳b,等待很长时间后再去干扰数据?
如果数据未锁定则状态修改也没关系,如果锁定了以前时间戳会被删除,执行会失败。
3. 用户在3是未知状态5秒后申请新的密钥,之后用之前的b来干扰?
不可能,如果申请新的密钥,则新时间戳一定>之前的b,执行肯定失败。
核销:(验证所有未知状态并锁定数据,非管理员也可进行) //建议:删除所有未知状态文件!
1. [网站] 找出未知记录时间戳最大值time_a以及本地时间time_w,生成查询密钥md5(tid/map/time_a/time_w)。
2. [存储] 如果时间<=time_a+5+[PHP执行时间]则拒绝执行,map若有多余则拒绝,否则校验所有文件,删除未知状态,并返回md5(tid/map/time_w+5)。
3. [网站] 如果当前map和map不同则拒绝,如果时间>time_w+5则拒绝执行,否则保存状态并锁定帖子,记录time_unlock=max(当前时间,time_w+5)。
4. [循环] 编辑时间<=time_unlock则拒绝,如果保存后再也不能编辑则不需要此步骤。
疑点:
核销至少等待最后一次执行密钥过期+存储端PHP执行时间结束后才可进行?
申请查询密钥后,本地又进行了一次执行密钥申请?此时map会改变,导致后续校验失败。
用于文件上传/删除/校验,此方法:
1. 存储端与数据端无需互通即可确保数据准确性。
2. 时间戳以存储端为主,避免二者同步问题。
3. 缺点是同一个文件不同操作间需间隔至少5秒。
执行与核销互为反操作,相互限制。存储端直到脚本停止也不给用户任何可乘之机!
自己琢磨几天想出来的,年龄大了智商不够用,如果有啥重大逻辑错误敬请提出!