权限判断优先用 if-else,因其支持任意布尔表达式、动态权限和模糊匹配;switch 仅适用于固定枚举或字符串且非 null 场景,Java 14+ 支持但灵活性不足。

权限判断该用 if 还是 switch?
Java 中权限判断本质是多分支逻辑,if-else if-else 最常用也最灵活;switch 从 Java 14 开始支持字符串和枚举,但仅适用于权限值为固定、有限且可穷举的场景(比如 "ADMIN"、"USER"、"GUEST")。若权限来自数据库或配置中心、含动态前缀(如 "ORDER:READ")、或需模糊匹配(如角色继承、权限通配),switch 直接失效。
- 用
if:支持任意布尔表达式,可组合hasRole("ADMIN") || hasPermission("SYSTEM:MANAGE") - 用
switch:必须确保输入非 null,否则抛NullPointerException;Java 17+ 可用switch表达式返回值,但无法短路求值 - 避免嵌套过深:三层以上
if建议拆成独立方法,例如canAccessOrderDetail(userId, orderId)
如何安全比对用户权限字符串?
权限字段常来自 HTTP Header、JWT payload 或数据库查询结果,直接用 .equals() 前必须防御 null 和空格。常见错误是写成 userRole == "ADMIN"(引用比较)或 userRole.equals("ADMIN")(未判空导致 NPE)。
- 统一用常量在前:例如
"ADMIN".equals(userRole),避免 NPE - 去除首尾空格:
"ADMIN".equals(userRole != null ? userRole.trim() : null) - 忽略大小写时用
"admin".equalsIgnoreCase(userRole),但注意 locale 敏感性(如土耳其语中i的大写不是I),生产环境建议显式指定Locale.ENGLISH
Spring Security 的 hasAuthority() 和自定义逻辑冲突怎么办?
当项目已引入 Spring Security,但部分接口需绕过其过滤器链(如内部 RPC 调用),或需组合多个权限条件(如“是 VIP 且订单金额 @PreAuthorize("hasAuthority('PAY:REFUND')")。
- 自定义权限检查方法应与 SecurityContext 解耦:不要直接调用
SecurityContextHolder.getContext().getAuthentication(),而是通过参数传入String userId或Setauthorities - 避免重复查库:将用户权限缓存在
ConcurrentHashMap或 Redis 中,设置合理 TTL(如 5 分钟),并监听权限变更事件主动清理 - 注意事务边界:在
@Transactional方法内调用权限判断,若权限数据刚插入但未提交,自定义逻辑可能读不到最新状态
public boolean canRefundOrder(String userId, BigDecimal amount) {
Set perms = permissionCache.get(userId);
boolean hasRefundAuth = perms != null && perms.contains("PAY:REFUND");
return hasRefundAuth && amount.compareTo(new BigDecimal("1000")) < 0;
}
权限校验放在 Controller 还是 Service 层?
Controller 层适合做粗粒度入口拦截(如验证 JWT 签名、基础角色),细粒度业务权限(如“只能删除自己创建的草稿”)必须下沉到 Service 层。否则 Controller 会膨胀,且单元测试难以覆盖真实权限路径。
立即学习“Java免费学习笔记(深入)”;
- Controller 示例:只校验
@PreAuthorize("hasAnyAuthority('CONTENT:EDIT', 'CONTENT:PUBLISH')"),不校验具体文章 ID 所属人 - Service 示例:在
deleteDraft(Long draftId)内部查draftRepository.findById(draftId),再比对draft.getAuthorId().equals(currentUserId) - 切忌在 MyBatis XML 中拼 SQL 权限条件(如
AND author_id = #{userId}),这会让权限逻辑散落、不可复用、难审计










