SecurityUtils 工具类
SecurityUtils 提供静态方法获取当前登录用户信息,无需查询数据库。
位置: blog-common/src/main/java/com/blog/common/utils/SecurityUtils.java
📖 API 参考
getCurrentUserId
获取当前登录用户的 ID
Long userId = SecurityUtils.getCurrentUserId();
实现原理:从 JwtAuthenticationDetails 中直接获取,性能优秀。
public static Long getCurrentUserId() {
Authentication authentication = SecurityContextHolder
.getContext()
.getAuthentication();
if (authentication != null &&
authentication.getDetails() instanceof JwtAuthenticationDetails details) {
return details.getUserId();
}
return null;
}
getCurrentUsername
获取当前登录用户名
String username = SecurityUtils.getCurrentUsername();
public static String getCurrentUsername() {
Authentication authentication = SecurityContextHolder
.getContext()
.getAuthentication();
if (authentication != null && authentication.getPrincipal() instanceof String username) {
return username;
}
return null;
}
getCurrentUserRoles
获取当前用户的角色列表
List<String> roles = SecurityUtils.getCurrentUserRoles();
// ["ROLE_USER", "ROLE_ADMIN"]
public static List<String> getCurrentUserRoles() {
Authentication authentication = SecurityContextHolder
.getContext()
.getAuthentication();
if (authentication != null) {
return authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toList());
}
return List.of();
}
hasRole
检查当前用户是否有指定角色
if (SecurityUtils.hasRole("ROLE_ADMIN")) {
// 管理员逻辑
}
public static boolean hasRole(String role) {
return getCurrentUserRoles().contains(role);
}
🔐 使用示例
Controller 中获取当前用户
@RestController
@RequestMapping("/api/v1/users")
public class UserController {
@GetMapping("/me")
public Result<UserVO> getCurrentUser() {
// ✅ 推荐:使用 SecurityUtils
Long userId = SecurityUtils.getCurrentUserId();
return Result.success(userService.getById(userId));
}
@PutMapping("/me")
public Result<Void> updateCurrentUser(@RequestBody UserDTO dto) {
// 强制设置为当前用户ID,防止越权
dto.setId(SecurityUtils.getCurrentUserId());
userService.updateByDto(dto);
return Result.success();
}
}
Service 中记录操作用户
@Service
public class ArticleServiceImpl {
public void publishArticle(ArticleDTO dto) {
// 设置作者为当前用户
dto.setAuthorId(SecurityUtils.getCurrentUserId());
articleMapper.insert(dto);
}
}
权限检查
public void deleteArticle(Long articleId) {
Article article = articleMapper.selectById(articleId);
// 只有作者或管理员可以删除
Long currentUserId = SecurityUtils.getCurrentUserId();
boolean isOwner = article.getAuthorId().equals(currentUserId);
boolean isAdmin = SecurityUtils.hasRole("ROLE_ADMIN");
if (!isOwner && !isAdmin) {
throw new BusinessException(ErrorCode.ACCESS_DENIED);
}
articleMapper.deleteById(articleId);
}
⚠️ 注意事项
1. 只在认证上下文中使用
// ✅ 在需要认证的接口中使用
@GetMapping("/me")
public Result<UserVO> getCurrentUser() {
Long userId = SecurityUtils.getCurrentUserId(); // 可用
}
// ❌ 在公开接口中使用会返回 null
@PostMapping("/register") // 无需认证
public Result<UserVO> register() {
Long userId = SecurityUtils.getCurrentUserId(); // null!
}
2. 避免在 Controller 参数中传 userId
// ❌ 不推荐:从请求参数获取(不安全)
@PutMapping("/users/{userId}")
public Result<Void> updateUser(@PathVariable Long userId) { }
// ✅ 推荐:从 SecurityContext 获取
@PutMapping("/me")
public Result<Void> updateCurrentUser() {
Long userId = SecurityUtils.getCurrentUserId();
}
3. 线程安全
SecurityContextHolder 默认使用 ThreadLocal,在同一线程内安全。
// ✅ 同步环境
Long userId = SecurityUtils.getCurrentUserId();
// ⚠️ 异步环境需要传递 SecurityContext
@Async
public void asyncTask() {
// SecurityContext 可能为空!
// 需要显式传递或使用 DelegatingSecurityContextAsyncTaskExecutor
}
📚 延伸阅读
- Security 概述 — 三链架构
- JWT 认证详解 — Token 实现