Commit 9f3e14a2 by Lizh

fix: 代码审查修复 — JWT密钥强度 + logout令牌失效 + cancelAuthUser空指针防护

- TokenHandle.createToken: 对 secret 做 SHA-256 哈希派生 256 位密钥,兼容 JJWT 0.12.x 强度要求
- TokenHandle.removeToken: 新增 Redis token 清除方法
- SysLoginController.logout: 调用 SysLoginService.logout() 清除 Redis 中登录态
- SysRoleController.cancelAuthUser: 添加 null 防护避免 NPE

Co-Authored-By: Claude <noreply@anthropic.com>
parent e5850d0c
......@@ -34,4 +34,9 @@ public interface SysLoginService {
* @return 前端路由树
*/
List<RouterVO> getRouters();
/**
* 退出登录,清除 Redis 中的 token
*/
void logout();
}
......@@ -163,4 +163,14 @@ public class SysLoginServiceImpl implements SysLoginService {
})
.collect(Collectors.toList());
}
@Override
public void logout() {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser != null && loginUser.getToken() != null) {
// 调用 TokenHandle 清除 Redis 中缓存的用户信息
tokenHandle.removeToken(loginUser.getToken());
log.info("用户[{}]退出登录,token 已失效", loginUser.getUsername());
}
}
}
......@@ -251,7 +251,10 @@ public class TokenHandle {
}
// 生成 JWT
byte[] keyBytes = secret.getBytes(java.nio.charset.StandardCharsets.UTF_8);
// 对 secret 做 SHA-256 哈希以派生足够长度的密钥(JJWT 0.12.x 要求 ≥256 位)
try {
java.security.MessageDigest digest = java.security.MessageDigest.getInstance("SHA-256");
byte[] keyBytes = digest.digest(secret.getBytes(java.nio.charset.StandardCharsets.UTF_8));
SecretKey signingKey = Keys.hmacShaKeyFor(keyBytes);
return Jwts.builder()
......@@ -263,6 +266,20 @@ public class TokenHandle {
.expiration(new java.util.Date(loginUser.getExpireTime()))
.signWith(signingKey)
.compact();
} catch (java.security.NoSuchAlgorithmException e) {
throw new RuntimeException("SHA-256 算法不可用,无法生成 JWT", e);
}
}
/**
* 删除用户令牌(退出登录时清除 Redis 缓存)
*
* @param token 令牌 UUID
*/
public void removeToken(String token) {
if (stringRedisTemplate != null && org.springframework.util.StringUtils.hasText(token)) {
stringRedisTemplate.delete(REDIS_TOKEN_PREFIX + token);
}
}
/**
......
......@@ -69,7 +69,7 @@ public class SysLoginController {
@PostMapping("/api/v2/logout")
@Operation(summary = "退出登录")
public R<Void> logout() {
log.info("用户退出登录");
sysLoginService.logout();
return R.ok();
}
}
......@@ -117,8 +117,13 @@ public class SysRoleController {
@RequiresPermissions("system:role:edit")
@PutMapping("/authUser/cancel")
public R<Void> cancelAuthUser(@RequestBody Map<String, Object> body) {
Long roleId = Long.valueOf(body.get("roleId").toString());
Long userId = Long.valueOf(body.get("userId").toString());
Object roleIdObj = body.get("roleId");
Object userIdObj = body.get("userId");
if (roleIdObj == null || userIdObj == null) {
return R.fail("roleId 和 userId 不能为空");
}
Long roleId = Long.valueOf(roleIdObj.toString());
Long userId = Long.valueOf(userIdObj.toString());
sysRoleService.cancelAuthUser(roleId, userId);
return R.ok();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment