JeecgBoot权限控制系统解析:以具体模块为例
1. JeecgBoot权限核心概念
JeecgBoot的权限控制基于经典的RBAC(基于角色的访问控制) 模型,并通过Shiro框架实现。它主要包括:
菜单权限:控制用户能看到哪些菜单(对应permission表)。
按钮权限:控制用户能否看到或操作页面上的按钮(如新增、删除、编辑等,使用v-has指令或@RequiresPermissions注解)
数据权限:控制用户能看到哪些数据(行级权限)或数据的哪些字段(列级权限)。
2. 具体代码权限实现解析
种养殖模块(地块、信息、产量管理)代码清晰地体现了JeecgBoot的权限设计。
首先我们要在数据库要有相应的表(权限表,用户表)
2.1 后端权限控制 (@RequiresPermissions)
在控制器中,使用@RequiresPermissions注解来声明访问特定接口所需的权限标识符。
// GbzntBreedingPlotsController.java - 添加地块
@AutoLog(value = "种养地块信息表-添加")
@PostMapping(value = "/add")
@RequiresPermissions("business:breedingPlots:add") // 权限注解
@ApiOperation(value="种养地块信息表-添加", notes="种养地块信息表-添加")
public Result<GbzntBreedingPlots> add(@RequestBody GbzntBreedingPlots gbzntBreedingPlots, HttpServletRequest request) {// ... 业务逻辑
}// GbzntBreedingInfoController.java - 编辑种养信息
@AutoLog(value = "种养信息表-编辑")
@PutMapping(value = "/edit")
@RequiresPermissions("breeding:breedingInfo:edit") // 权限注解
@ApiOperation(value="种养信息表-编辑", notes="种养信息表-编辑")
public Result<GbzntBreedingInfo> edit(@RequestBody GbzntBreedingInfo gbzntBreedingInfo) {// ... 业务逻辑
}
注解解析:
@RequiresPermissions("business:breedingPlots:add"):表示调用此接口需要business:breedingPlots:add这个权限标识(这个表示就是在数据库权限表中)。
扩展:关于Shiro在这个平台的作用
Shiro 的核心流程可概括为 “认证 → 授权 → 业务处理 → 退出” 四步,围绕其核心组件(Subject、SecurityManager、Realm)高效完成权限管控,以下是简洁且关键的流程拆解:
1. 初始化:核心组件就绪
Shiro 启动时,需完成基础配置(如配置文件、代码注入),核心是初始化 SecurityManager(Shiro 核心控制器),并为其关联 Realm(数据桥梁,负责从数据库 / 缓存等获取用户、权限数据)。
此时 SecurityManager 成为全局权限控制的 “大脑”,Realm 则是它的 “数据源”。
2. 认证(Authentication):验证 “你是谁”
即验证用户身份(如账号密码登录),流程如下:
获取 Subject:通过 SecurityUtils.getSubject() 拿到当前用户的抽象对象(Subject,无论登录与否都存在)。
提交身份凭证:用户输入账号密码后,封装为 UsernamePasswordToken 对象,调用 subject.login(token) 发起认证。
SecurityManager 转发:Subject 本身不处理认证,直接将 token 交给 SecurityManager。
Realm 校验:SecurityManager 调用关联的 Realm,执行 doGetAuthenticationInfo() 方法 ——Realm 从数据源查询用户信息,返回包含正确密码的 AuthenticationInfo。
凭证比对:Shiro 自动比对 token 中的提交密码与 Realm 返回的正确密码(支持加密比对,如 MD5、SHA),比对成功则认证通过,失败则抛出异常(如 IncorrectCredentialsException)。
3. 授权(Authorization):验证 “你能做什么”
认证通过后,校验用户是否有操作某个资源的权限,流程如下:
触发授权检查:业务中通过 subject.hasRole("admin")(检查角色)或 subject.isPermitted("user:edit")(检查权限)触发授权。
SecurityManager 转发:Subject 将授权请求交给 SecurityManager。
Realm 加载权限:SecurityManager 调用 Realm 的 doGetAuthorizationInfo() 方法 ——Realm 从数据源查询当前用户的角色(Roles)和权限(Permissions),返回 AuthorizationInfo。
权限判断:Shiro 比对用户的权限集合与当前请求的权限 / 角色,返回 “允许” 或 “拒绝”(拒绝时抛出 UnauthorizedException)。
4. 业务处理:权限通过后的正常操作
授权通过后,用户即可执行对应的业务逻辑(如查看页面、修改数据),Shiro 不再干预,直至用户主动退出或会话过期。
5. 退出(Logout):清除身份信息
用户调用 subject.logout() 时,Shiro 会:
清除当前 Subject 的认证状态(标记为 “未登录”);
销毁用户会话(Session);
触发退出相关的监听器(如需要)。
在jeeboot中的运用
1. 身份认证 (Authentication) - 你是谁?
作用:验证用户的身份,即“登录”过程。
JeecgBoot实现:当用户输入用户名密码登录时,Shiro会接管认证流程。它调用配置好的
Realm
(通常是JeecgBoot自定义的ShiroRealm
),从数据库中查询用户信息,比对密码(通常经过加密),并创建用户的身份标识。
2. 授权 (Authorization) - 你能做什么?
(这是代码中最直观的部分)
作用:判断已认证的用户是否拥有执行某个操作的权限。
JeecgBoot实现:这是Shiro最核心的作用。通过您代码中的
@RequiresPermissions
注解,Shiro的拦截器会在API被调用前进行权限校验。
工作原理流程:
注解声明:您在Controller方法上声明权限点。
@RequiresPermissions("business:breedingPlots:add") // <-- 权限标识
@PostMapping("/add")
public Result add(...) { ... }
拦截校验:Shiro的 AuthorizationFilter 会拦截请求,解析出请求需要 "business:breedingPlots:add" 权限。
权限查询:Shiro调用 Realm 的 doGetAuthorizationInfo 方法,获取当前用户的所有权限列表(通常是在用户登录时已缓存到Shiro的 PrincipalCollection 中)。
决策判断:Shiro将注解要求的权限与用户拥有的权限列表进行比对。
拥有该权限 → 放行,执行Controller方法。
不拥有该权限 → 抛出 UnauthorizedException 异常,最终返回 HTTP 403 Forbidden。
2.2 权限标识符设计
JeecgBoot推荐的权限标识符格式通常为模块:功能:操作:
business:breedingPlots:add:表示“业务模块:种养地块功能:添加操作”
breeding:breedingInfo:edit:表示“种养殖模块:种养信息功能:编辑操作”
这种命名方式清晰且易于管理。
2.3 权限配置流程
要让上述代码中的权限控制生效,需要在JeecgBoot后台进行配置:
菜单与权限配置:进入“系统管理”->“菜单管理”,添加一个菜单(类型选择“按钮”或“权限”),并在“权限标识”字段中填入business:breedingPlots:add。
角色授权:进入“系统管理”->“角色管理”,选择某个角色(如“管理员”),点击“授权”,在弹出框中勾选上一步创建的权限标识。
用户关联角色:为用户分配拥有相应权限的角色。
3.最佳实践与建议
权限标识符设计规范:
遵循 <系统|模块>:<实体>:<操作> 的约定,如 system:user:add, farming:plot:delete。保持全局唯一且含义清晰。
在项目启动前进行统一规划,避免后期混乱。
后端权限控制:
重要操作必须在后端加上 @RequiresPermissions 注解。前端权限控制只是为了用户体验,后端校验是安全的关键,绝不能省略。
对于简单的 CRUD,可以使用 JeecgBoot 的代码生成器,它会自动为生成的 Controller 添加对应的权限注解,极大提高开发效率。
权限变更的实时性:
用户权限修改后,需要用户重新登录才能生效,因为权限数据通常在登录时加载并缓存。如果要求实时生效,需要设计一套复杂的权限缓存刷新机制。