本文目录导读:

- 基于RBAC(基于角色的访问控制)
- 基于Spring Security + JWT的权限控制
- 基于注解的细粒度权限控制(方法级别)
- 基于过滤器链的URL级别权限控制
- 基于ABAC(基于属性的访问控制)
- 最佳实践建议
- 实际项目案例结构
在Java中实现权限控制,通常有几种主流方案,具体选择取决于你的应用类型(单体应用、微服务、分布式系统)和安全级别需求,以下是几种最常用的实现方式及案例:
基于RBAC(基于角色的访问控制)
这是最常见也是最成熟的权限控制模型。
核心思想:
- 用户(User):系统的使用者
- 角色(Role):权限的集合(如管理员、普通用户)
- 权限(Permission):具体的操作许可(如创建文章、删除用户)
数据结构设计:
-- 用户表
CREATE TABLE `sys_user` (
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
`username` VARCHAR(50) NOT NULL,
`password` VARCHAR(100) NOT NULL
);
-- 角色表
CREATE TABLE `sys_role` (
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
`role_name` VARCHAR(50) NOT NULL,
`role_code` VARCHAR(50) NOT NULL UNIQUE
);
-- 权限表
CREATE TABLE `sys_permission` (
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
`perm_name` VARCHAR(50) NOT NULL,
`perm_code` VARCHAR(50) NOT NULL UNIQUE -- 如 "user:create"
);
-- 用户-角色关系表
CREATE TABLE `sys_user_role` (
`user_id` BIGINT,
`role_id` BIGINT,
PRIMARY KEY (`user_id`, `role_id`)
);
-- 角色-权限关系表
CREATE TABLE `sys_role_permission` (
`role_id` BIGINT,
`permission_id` BIGINT,
PRIMARY KEY (`role_id`, `permission_id`)
);
Spring Security + RBAC 实现示例:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
// 基于权限码控制
.requestMatchers("/api/user/create").hasAuthority("user:create")
.requestMatchers("/api/user/delete").hasAuthority("user:delete")
// 基于角色控制(注意角色需要加ROLE_前缀)
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults());
return http.build();
}
}
基于Spring Security + JWT的权限控制
适用于前后端分离的单体或微服务架构。
实现流程:
// 1. JWT Token工具类
@Component
public class JwtTokenUtil {
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
// 将用户的角色和权限加入JWT
claims.put("roles", userDetails.getAuthorities());
return Jwts.builder()
.setClaims(claims)
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 3600000))
.signWith(SignatureAlgorithm.HS512, "secret")
.compact();
}
}
// 2. JWT认证过滤器
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) {
String token = request.getHeader("Authorization");
if (token != null) {
// 解析token并设置SecurityContext
Authentication auth = jwtTokenUtil.parseToken(token);
SecurityContextHolder.getContext().setAuthentication(auth);
}
chain.doFilter(request, response);
}
}
基于注解的细粒度权限控制(方法级别)
使用Spring的@PreAuthorize注解实现方法级别的权限控制:
@RestController
@RequestMapping("/api/users")
public class UserController {
// 基于角色控制
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/all")
public List<User> getAllUsers() {
return userService.findAll();
}
// 基于权限码控制
@PreAuthorize("hasAuthority('user:create')")
@PostMapping
public User createUser(@RequestBody User user) {
return userService.create(user);
}
// 基于表达式控制(用户只能操作自己的数据)
@PreAuthorize("#id == authentication.principal.id or hasRole('ADMIN')")
@PutMapping("/{id}")
public User updateUser(@PathVariable Long id, @RequestBody User user) {
return userService.update(id, user);
}
}
// 启用方法级别的安全控制
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig {
// 配置类
}
基于过滤器链的URL级别权限控制
适用于前后端分离的项目,在网关或应用层进行统一拦截:
@Component
public class PermissionFilter implements Filter {
@Autowired
private PermissionService permissionService;
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String requestURI = httpRequest.getRequestURI();
String method = httpRequest.getMethod();
// 获取当前用户权限
User currentUser = getCurrentUser();
// 检查用户是否有访问该URL的权限
if (permissionService.checkPermission(currentUser, method, requestURI)) {
chain.doFilter(request, response);
} else {
// 返回403禁止访问
response.getWriter().write("Access Denied");
}
}
}
基于ABAC(基于属性的访问控制)
适用于更复杂的业务场景,支持基于用户属性、环境属性、资源属性进行动态决策:
public class ABACPolicyEngine {
public boolean evaluate(Policy policy, Subject subject, Resource resource, Environment env) {
// 示例规则:只有创建者或管理员可以删除文档
return policy.getRules().stream().anyMatch(rule -> {
if (rule.getAction().equals("delete_document")) {
// 检查用户是否为管理员
boolean isAdmin = subject.hasRole("ADMIN");
// 检查用户是否为文档创建者
boolean isOwner = resource.getAttribute("ownerId").equals(subject.getId());
return isAdmin || isOwner;
}
return false;
});
}
}
最佳实践建议
-
选择合适粒度:
- URL级别:适合统一的权限拦截,性能好
- 方法级别:更精细的控制,适合复杂业务
- 数据级别:控制到具体的数据行(如用户只能看自己创建的数据)
-
缓存策略:
@Service public class PermissionService { @Cacheable(value = "userPermissions", key = "#userId") public Set<String> getUserPermissions(Long userId) { // 此处查询数据库获取用户所有权限 return permissionDAO.findByUserId(userId); } } -
性能优化:
- 权限数据使用Redis缓存
- 使用Bloom Filter进行快速权限判断
- 避免在循环中重复查询权限
-
安全考虑:
- 前端只显示用户有权限的菜单/按钮(体验优化,但不可作为安全依据)
- 后端必须做全面的权限校验(前端限制不安全)
- 防止权限绕过(如修改URL参数、篡改请求方式等)
实际项目案例结构
// 一个完整的权限校验服务
@Service
public class AccessControlService {
// 检查是否有某个操作权限
public boolean hasPermission(String permissionCode) {
// 获取当前登录用户
User currentUser = getCurrentUser();
// 超级管理员拥有所有权限
if (currentUser.isSuperAdmin()) {
return true;
}
// 从缓存或数据库获取用户权限列表
Set<String> permissions = getUserPermissions(currentUser.getId());
return permissions.contains(permissionCode);
}
// 检查是否拥有某个角色
public boolean hasRole(String roleCode) {
User currentUser = getCurrentUser();
return currentUser.getRoles().stream()
.anyMatch(role -> role.getRoleCode().equals(roleCode));
}
// 检查是否拥有所有指定权限(AND逻辑)
public boolean hasAllPermissions(String... permissionCodes) {
return Arrays.stream(permissionCodes)
.allMatch(this::hasPermission);
}
// 检查是否拥有任一指定权限(OR逻辑)
public boolean hasAnyPermission(String... permissionCodes) {
return Arrays.stream(permissionCodes)
.anyMatch(this::hasPermission);
}
}
选择哪种方式取决于你的具体需求:如果是简单的管理后台,RBAC通常足够;如果是复杂的多租户SaaS系统,可能需要ABAC;如果追求开发效率,直接用Spring Security的注解方式即可,建议从简单开始,逐步演进,避免过度设计。