在投票类项目中,用户权限管理是保障系统安全的核心模块,通常需要区分普通投票用户、投票管理员、系统管理员等不同角色,限制不同角色的操作范围,比如普通用户只能参与投票,管理员可以创建投票、查看投票结果等。合理的权限设计能避免越权操作,提升系统的稳定性和安全性。

权限模型设计
简易投票权限管理可以采用RBAC(基于角色的访问控制)模型,核心包含三个实体:用户、角色、权限。用户和角色是多对多关系,角色和权限也是多对多关系,通过角色作为中间层关联用户和权限,降低权限分配的复杂度。
我们可以设计如下基础表结构:
- 用户表(user):存储用户基本信息,包含用户id、用户名、密码等字段
- 角色表(role):存储角色信息,包含角色id、角色名称、角色描述等字段
- 权限表(permission):存储权限信息,包含权限id、权限标识、权限描述等字段
- 用户角色关联表(user_role):存储用户和角色的对应关系
- 角色权限关联表(role_permission):存储角色和权限的对应关系
核心实体类定义
首先定义对应的Java实体类,这里以MyBatis-Plus框架为例,实体类代码如下:
// 用户实体类
public class User {
private Long id;
private String username;
private String password;
// 用户关联的角色集合
private List<Role> roles;
// getter和setter方法省略
}
// 角色实体类
public class Role {
private Long id;
private String roleName;
private String roleDesc;
// 角色关联的权限集合
private List<Permission> permissions;
// getter和setter方法省略
}
// 权限实体类
public class Permission {
private Long id;
private String permissionKey;
private String permissionDesc;
// getter和setter方法省略
}
权限校验功能实现
我们可以使用Spring Security框架快速实现权限校验逻辑,首先配置Spring Security,定义不同角色对应的访问权限规则:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 设置自定义的用户详情服务,用于加载用户信息和权限
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// 投票查看接口,普通用户和管理员都可以访问
.antMatchers("/vote/view/**").hasAnyRole("USER", "ADMIN")
// 投票提交接口,只有普通用户和投票管理员可以访问
.antMatchers("/vote/submit").hasAnyRole("USER", "VOTE_ADMIN")
// 投票创建接口,只有投票管理员和系统管理员可以访问
.antMatchers("/vote/create").hasAnyRole("VOTE_ADMIN", "SYSTEM_ADMIN")
// 投票结果统计接口,只有管理员可以访问
.antMatchers("/vote/result/**").hasAnyRole("VOTE_ADMIN", "SYSTEM_ADMIN")
// 其他请求需要认证
.anyRequest().authenticated()
.and()
// 开启表单登录
.formLogin()
.and()
// 关闭csrf防护,方便测试
.csrf().disable();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
接下来实现自定义的用户详情服务,从数据库中加载用户的角色和权限信息:
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Autowired
private RoleMapper roleMapper;
@Autowired
private PermissionMapper permissionMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 查询用户信息
User user = userMapper.selectByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("用户不存在");
}
// 查询用户的角色
List<Role> roles = roleMapper.selectByUserId(user.getId());
// 查询角色对应的权限
List<GrantedAuthority> authorities = new ArrayList<>();
for (Role role : roles) {
// 添加角色前缀,Spring Security默认角色需要以ROLE_开头
authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getRoleName()));
// 查询角色的权限
List<Permission> permissions = permissionMapper.selectByRoleId(role.getId());
for (Permission permission : permissions) {
authorities.add(new SimpleGrantedAuthority(permission.getPermissionKey()));
}
}
// 返回Spring Security的User对象
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(),
authorities
);
}
}
自定义权限注解实现
如果需要在方法层面更灵活地控制权限,可以自定义权限注解,实现更细粒度的权限校验:
// 自定义权限校验注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequiresPermission {
// 需要的权限标识
String value();
}
然后实现对应的权限校验切面:
@Aspect
@Component
public class PermissionAspect {
@Autowired
private HttpServletRequest request;
@Around("@annotation(requiresPermission)")
public Object checkPermission(ProceedingJoinPoint joinPoint, RequiresPermission requiresPermission) throws Throwable {
// 获取当前登录用户
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
throw new RuntimeException("用户未登录");
}
// 获取用户权限
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
String needPermission = requiresPermission.value();
// 校验用户是否拥有对应权限
boolean hasPermission = authorities.stream()
.anyMatch(auth -> auth.getAuthority().equals(needPermission));
if (!hasPermission) {
throw new RuntimeException("没有操作权限");
}
// 有权限则执行原方法
return joinPoint.proceed();
}
}
使用时只需要在对应的方法上添加注解即可:
@RestController
@RequestMapping("/vote")
public class VoteController {
// 只有拥有vote:create权限的用户可以访问
@RequiresPermission("vote:create")
@PostMapping("/create")
public String createVote(@RequestBody Vote vote) {
// 创建投票的逻辑
return "创建投票成功";
}
}
常见问题说明
- 角色名称在Spring Security中默认需要添加
ROLE_前缀,配置权限规则时需要注意前缀匹配问题 - 密码存储必须使用加密方式,不要明文存储用户密码,这里使用BCryptPasswordEncoder进行加密
- 如果需要动态修改权限,不需要重启服务,只需要更新数据库中的角色权限关联数据,下次用户登录时就会加载最新的权限信息
Java投票权限管理用户权限Spring_Security修改时间:2026-07-01 21:57:35