一条测评链接发到受测者手里,怎么保证它只被本人打开、只能提交一次、发错了还能立刻让它失效?这三个要求——防转发、防重放、可作废——听起来是三件事,落到链接末尾那串 Token 上,是同一处设计的三个侧面。Token 设计得糙,三个要求会互相打架;设计得对,它们能在一处一并满足。
防转发的核心是让 Token 和具体的受测者绑定,而不是做成一串谁拿到都能用的通用口令。发放时就把这条链接绑给某个人,Token 承载的是“这次测评、这个人”的身份,服务端校验时确认打开链接的和被指派的是同一个。这样即便链接被截图转发到群里,别人点开也对不上身份,顶多看到一句无权作答。想更严一点,可以要求打开链接时补一个只有本人知道的信息,或者在受测者首次打开后就把链接和设备、登录态关联起来,后续换个人、换台设备就走不通。
防重放要解决的是同一条链接、同一份作答被提交多次——可能是网络重试,也可能是有人拿旧链接反复刷。做法是给每次作答一个一次性的凭据:Token 对应一个服务端可查的状态,提交成功后这条 Token 就被标记为已用,再次带着同样的 Token 来提交,服务端直接拒掉。关键在状态记在服务端,而不是只靠前端按钮置灰——前端能被绕过,服务端的“已用”标记才是真正拦得住重复提交的那道。橙星云给每条测评链接配的就是带状态、可核销的一次性凭据,提交后即置为已完成,同一条链接无法再次交卷。
可作废意味着这条 Token 的效力不能是永久的,得能被主动收回。最基本的是加有效期,链接过一段时间自动失效,避免半年前发出去的链接还能作答;更主动的是让管理员随时手动作废某条链接,比如发错了人、受测者换了、这批测评临时取消。要做到随时作废,Token 就不能是那种“自己包含全部信息、服务端不查库也能验”的无状态设计——那种链接一旦发出去,在过期前没法单独撤销。把 Token 的有效性挂在服务端一份可改的状态上,作废就只是把那份状态改掉。
这也是三个要求能兼顾的关键:与其把身份、次数、有效期全塞进一串自证明的 Token,不如让 Token 只做一把指针,真正的“绑给谁、用没用过、还有没有效”都记在服务端。防转发靠身份绑定,防重放靠一次性核销,可作废靠可改的状态,三者共用同一份服务端记录,改一处就能同时影响。代价是每次校验都要查一次服务端,换来的是发出去的每条链接始终在掌控之内,而不是撒出去就再也收不回。
