【问题标题】:Force Logout of user on multiple devices using JWT使用 JWT 在多个设备上强制用户注销
【发布时间】:2021-02-18 00:20:59
【问题描述】:
我们有一个现有的 REST API,目前正在使用 JWT。
客户端要求用户一次只能使用一台设备。例如,如果用户从 iOS 设备登录然后登录 Android 设备,那么 iOS 设备应该被“强制”退出。
由于我们使用的是 JWT,我们不会跟踪令牌,除了用户单击注销时的令牌黑名单。
我研究了如何“强制”注销用户,似乎我们需要跟踪用户使用的最后一个令牌,然后在我们检测到新的登录时使其无效。
上面没有更清洁/替代的方法吗?
【问题讨论】:
标签:
rest
authentication
jwt
【解决方案1】:
假设您使用 JWT 作为 Bearer 令牌,根据您的要求,“跟踪用户使用的最后一个令牌,然后在我们检测到新登录时使该令牌失效”可能还不够。
由于不记名令牌(与是否为 JWT 无关)由客户端发送,因此客户端也知道令牌,这允许发送方将令牌从一台设备复制并粘贴到另一台设备(或发出请求,包括来自各种设备的相同令牌)。
您的要求听起来像是适当会话管理的标准用例,例如用于用户代理绑定。
【解决方案2】:
以下是实现您的要求的步骤:
第 1 步:保存上次用户为更新密码或从所有设备注销而执行的活动的时间戳
-
添加一列 lastSessionResetDate 以将上次密码更新日期存储在您的用户表中
-
在执行忘记密码/更改密码 API 或从所有设备注销时,更新 lastSessionResetDate
第 2 步:在生成 JWT 令牌时,在 JWT 声明中设置 lastSessionResetDate
生成令牌时设置声明的示例
//make a claims map (`Claim extends Map<String, Object>`)
Map<String, Object> claims = new HashMap<>();
claims.put(CLAIM_KEY_USERNAME, user.getUserName());
claims.put(CLAIM_KEY_AUDIENCE, "web");
claims.put(CLAIM_KEY_CREATED, new Date());
claims.put(CLAIM_KEY_LAST_SESSION_RESET, user.lastSessionResetDate());
//set claims and build JWT
return Jwts.builder().setClaims(claims).setSubject(user.getUserName())
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + yourTokenValidity))
.signWith(SignatureAlgorithm.HS512,"yourSecretEncodedBase64")
.compact();
你可以在解析 JWT 令牌时获取任何声明值。
第 3 步:验证用户和会话的时间
通过 JWT 获取用户实体后,检查 lastSessionResetDate 是否有效,否则未授权请求。
您必须已经从数据库中获取用户,因此您不需要进行任何其他查询,因为我们新添加的列 lastSessionResetDate 将是同一查询结果的一部分。 (您只需添加一个 if-else 块)。
注意:您还可以获得用户回复log-me-out-from-other-devices的提示值
希望你有一个想法,快乐编码!