我有关于 Spring MVC 控制器范围和 REST 服务的问题。我有几个 REST 服务,它们在响应中返回一个令牌,以便我稍后可以重新创建应用程序的状态,但我不希望用户两次使用相同的令牌,因此我决定保存一个唯一标识符在令牌内部以及 HttpServletRequest 中,因此我可以在收到请求时检查它(每个请求中都会生成一个新标识符)。
所以,我的问题是:
这是不可能实现的 无需在某处跟踪令牌。这种安全模式需要一些权衡,处理它。
给用户一个令牌并在服务器端跟踪它,就像白名单:
403
)来拒绝请求。此外,请考虑为令牌分配一个到期日期,并拒绝任何带有过期令牌的服务器请求。
关于您的性能问题:请记住,过早的优化是万恶之源。在出现性能问题并且您已经证明性能问题来自于您存储令牌的方式之前,您不应该进行优化。例如,您可以开始将令牌存储在数据库中,然后考虑在内存中进行缓存。但在解决您当前没有的问题时请务必小心。
如果您选择 JWT,有一些 Java 库可以颁发和验证 JWT 令牌,例如:
jti
声明应用于在代币上存储代币标识符。验证令牌时,请通过检查 jti
声明的值与您在服务器端拥有的令牌标识符来确保其有效。
对于令牌标识符,您可以使用 UUID。在 Java 中,它很简单:
String uuid = UUID.randomUUID().toString();
由于 HttpSession#getId() 是唯一的,您可以使用它来创建唯一的令牌:
// pseudo code
String token = httpSession.getId() + "-" + System.currentTimeMillis();
您还可以创建自己的计数器。
这是我的两种预防方法
禁用提交按钮: 我们可以在函数调用 HTTP 请求之前禁用提交按钮,并在完成获取 HTTP 响应后再次启用它。此技术对于需要较长时间(超过 5 秒)才能完成的过程非常有效。由于急于得到结果,用户无法再次点击。此外,我们可能会显示一个加载框以获得良好的体验。
发出请求token/id: 这种技术实际上比较复杂并且难以实现,但是感谢一个好的框架(例如Spring Boot)使这变得更容易。在讲代码实现之前,我们先来说一下机制; 当表单页面加载时,发出新的requestId 在调用后端服务之前,将发出的 requestId 放入 HTTP header 后端服务识别 requestId 是否已注册 如果 requestId 已经注册,那么我们可以将其标记为违规请求