🐛 认证审核接口改用菜单权限码,并补回被漏掉的审核岗位

原写法 @PreAuth("hasAnyRole('administrator','admin')") 有两个实际缺陷:

1. 库中**并不存在 admin 角色**(实查 blade_role:超级管理员 administrator、
   运管 yunguan、财务 caiwu、录单员 ludan…),该分支永远不成立;
2. 真正承担认证审核的「运管」岗位**被排除在外**——即审核功能上线后没人能审。

改为按本项目的权限模型走菜单码(票 01 已建好这四个码):
  cert_certification_audit_driver / _vehicle(列表与详情)
  cert_certification_audit_driver_audit / _vehicle_audit(审核动作)

用 SpEL 而非 @PreAuth(menu = "..."),是因为同一组接口由 bizType 区分同时服务
司机与车辆两侧,单值 menu 表达不了「二者之一」。

已核对框架实现:AuthAspect 把 value 交给 SpEL 求值,root object 即 AuthFun,
而 hasMenu 是它的公开方法,故该表达式可用;menu() 非空时才会先行校验。

73 个测试通过。
This commit is contained in:
2026-10-02 17:05:42 +08:00
parent d61f1bcae4
commit 60c1d626a2
@@ -56,12 +56,31 @@ import org.springframework.web.bind.annotation.RestController;
@Tag(name = "认证审核", description = "管理端司机认证与车辆认证审核")
public class CertificationAuditController extends BladeController {
/**
* 待审列表与详情的权限:司机或车辆任一审核菜单即可。
* <p>
* 用菜单码而不是角色名——本项目的权限走「角色-菜单」授权,
* 写死角色名会漏掉实际承担审核的岗位(例如「运管」),
* 也会在角色改名后静默失效。
* <p>
* 用 SpEL 而非 {@code @PreAuth(menu = "...")},是因为同一组接口同时服务
* 司机与车辆两侧(由 {@code bizType} 区分),单值 menu 表达不了「二者之一」。
*/
private static final String AUDIT_MENU_EXPRESSION =
"hasMenu('cert_certification_audit_driver') or hasMenu('cert_certification_audit_vehicle')";
/**
* 审核动作的权限:司机或车辆任一「审核」按钮权限即可
*/
private static final String AUDIT_ACTION_MENU_EXPRESSION =
"hasMenu('cert_certification_audit_driver_audit') or hasMenu('cert_certification_audit_vehicle_audit')";
private final ICertAuditService certAuditService;
@GetMapping("/pending-page")
@ApiOperationSupport(order = 1)
@Operation(summary = "待审列表", description = "按认证对象类型分页查询审核中的记录,按提交时间倒序")
@PreAuth("hasAnyRole('administrator','admin')")
@PreAuth(AUDIT_MENU_EXPRESSION)
public R<IPage<TransportCertRecordVO>> pendingPage(
@Parameter(description = "认证对象类型:driver-司机,vehicle-车辆", required = true)
@RequestParam String bizType,
@@ -75,7 +94,7 @@ public class CertificationAuditController extends BladeController {
@GetMapping("/detail")
@ApiOperationSupport(order = 2)
@Operation(summary = "审核详情", description = "同时返回待审快照与当前生效值,供前端做字段级对比")
@PreAuth("hasAnyRole('administrator','admin')")
@PreAuth(AUDIT_MENU_EXPRESSION)
public R<CertAuditDetailVO> detail(
@Parameter(description = "认证记录主键", required = true) @RequestParam Long id) {
return R.data(certAuditService.detail(id));
@@ -84,7 +103,7 @@ public class CertificationAuditController extends BladeController {
@PostMapping("/audit")
@ApiOperationSupport(order = 3)
@Operation(summary = "审核认证记录", description = "通过使该记录成为生效快照;驳回只终结该记录,生效快照不变")
@PreAuth("hasAnyRole('administrator','admin')")
@PreAuth(AUDIT_ACTION_MENU_EXPRESSION)
public R<Boolean> audit(
@Parameter(description = "认证记录主键", required = true) @RequestParam Long id,
@Parameter(description = "是否通过", required = true) @RequestParam Boolean pass,