Shiro权限注解案例

wen java案例 2

本文目录导读:

Shiro权限注解案例

  1. 为什么需要Shiro权限注解?
  2. Shiro核心注解全解析
  3. 案例一:基于RBAC的角色控制(@RequiresRoles)
  4. 案例二:细粒度权限码校验(@RequiresPermissions)
  5. 案例三:登录状态强制拦截(@RequiresAuthentication + @RequiresUser)
  6. 案例四:注解与Spring AOP的整合陷阱(代理失效)
  7. 案例五:权限注解的国际化与错误处理策略
  8. 高频问答:为什么我的注解不生效?如何自定义权限注解?


Shiro权限注解实战指南:从入门到精通,5个案例解锁细粒度访问控制**


目录导读

  1. 为什么需要Shiro权限注解?——传统权限管理的痛点
  2. Shiro核心注解全解析:@RequiresRoles / @RequiresPermissions / @RequiresAuthentication
  3. 基于RBAC的角色控制(@RequiresRoles)
  4. 细粒度权限码校验(@RequiresPermissions)
  5. 登录状态强制拦截(@RequiresAuthentication + @RequiresUser)
  6. 注解与Spring AOP的整合陷阱(代理失效问题)
  7. 权限注解的国际化与错误处理策略
  8. 高频问答:为什么我的注解不生效?如何自定义权限注解?

为什么需要Shiro权限注解?

在传统的Web应用中,权限校验往往通过if (subject.hasRole("admin"))硬编码写在业务逻辑里,导致代码臃肿、维护成本极高,而Shiro权限注解通过声明式编程,将权限规则直接标注在Controller或Service方法上,实现了“权限即配置”的核心理念,它不仅能够减少重复代码,还能通过统一的权限拦截器确保所有访问都经过安全校验,避免遗漏,根据官方文档,Shiro注解结合Spring Boot后,能提升约40%的开发效率。

Shiro核心注解全解析

  • @RequiresRoles("admin"):要求当前Subject拥有指定角色,支持逻辑OR(多个值)和AND(逻辑与)。
  • @RequiresPermissions("user:delete"):要求用户具备特定权限码,支持通配符(如user:*)。
  • @RequiresAuthentication:要求用户已登录(即subject.isAuthenticated()为真)。
  • @RequiresUser:要求用户已登录或“记住我”状态。
  • @RequiresGuest:要求当前为游客身份。
    这些注解的本质是通过AOP(面向切面编程)拦截方法执行,在方法调用前检查权限,未通过则抛出AuthorizationException

案例一:基于RBAC的角色控制(@RequiresRoles)

场景:后台管理系统中,仅允许“运营人员”访问数据报表接口。

@RestController
@RequestMapping("/report")
public class ReportController {
    @GetMapping("/daily")
    @RequiresRoles("operator")  // 支持多个角色:@RequiresRoles({"operator","admin"})
    public String getDailyReport() {
        return "日均数据报告";
    }
}

关键点:默认情况下,多个角色值之间是逻辑或关系,若需“同时拥有多个角色”,需使用logical = Logical.AND属性,角色名称需与RealmdoGetAuthorizationInfo分配的角色一致。

案例二:细粒度权限码校验(@RequiresPermissions)

场景:订单模块中,删除订单是敏感操作,需要order:delete权限码。

@DeleteMapping("/order/{id}")
@RequiresPermissions(value = "order:delete", logical = Logical.AND)
public String deleteOrder(@PathVariable Long id) {
    // 业务逻辑
    return "订单已删除";
}

进阶用法:Shiro支持通配符权限,例如@RequiresPermissions("order:*")可匹配所有订单操作,但实际开发中更推荐明确权限码以避免越权,权限码的命名规范建议采用资源:操作格式,如user:createuser:update

案例三:登录状态强制拦截(@RequiresAuthentication + @RequiresUser)

区别@RequiresAuthentication强制要求会话内登录,而@RequiresUser允许“记住我”的静默登录状态。

@GetMapping("/profile")
@RequiresUser  // 使用@RequiresAuthentication则记住我用户无法访问
public String viewProfile() {
    return "个人中心";
}

适用场景:涉及支付、密码修改等高风险操作时,建议使用@RequiresAuthentication,防止记住我状态下的CSRF风险。

案例四:注解与Spring AOP的整合陷阱(代理失效)

常见错误:注解标注在私有方法同一个类内部调用时,注解会失效,因为Spring AOP基于动态代理,如果方法通过this.method()内部调用,不会经过代理对象。
解决方案

  • 将注解方法拆分为独立Bean,并通过@Autowired注入调用。

  • 推荐使用spring.aop.proxy-target-class=true强制CGLIB代理。
    代码示例

    @Service
    public class OrderService {
      @Autowired
      private OrderService self; // 注入自身代理
      public void execute() {
          self.deleteOrder(); // 通过代理调用,注解生效
      }
      @RequiresPermissions("order:delete")
      public void deleteOrder() { ... }
    }

案例五:权限注解的国际化与错误处理策略

当权限不足时,Shiro默认抛出AuthorizationException,前端会收到500错误,优雅的处理方式是全局捕获并返回标准JSON:

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(AuthorizationException.class)
    @ResponseBody
    public ResponseEntity<String> handleAuthException() {
        return ResponseEntity.status(HttpStatus.FORBIDDEN)
                .body("{\"code\":403,\"msg\":\"无访问权限\"}");
    }
}

国际化:可以结合LocaleResolver,在错误消息中动态替换ResourceBundle中的key。

高频问答:为什么我的注解不生效?如何自定义权限注解?

问答1:注解写在Controller上无效?
检查是否引入shiro-spring-boot-web-starter,并在启动类排除SecurityAutoConfiguration,确保ShiroFilterFactoryBean中filterChainDefinitions没有显式拦截同一路径(如/** = authc),否则会先于注解执行。

问答2:如何自定义组合注解?
可以创建组合注解,

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@RequiresAuthentication
@RequiresPermissions("admin:operate")
public @interface AdminOperation {}

然后直接使用@AdminOperation,同时具备登录+权限双校验。

问答3:注解支持SpEL表达式吗?
官方不支持,若需复杂表达式,需自定义AOP切面,在切面中调用SecurityUtils.getSubject()校验权限。



Shiro权限注解并非银弹,它适用于静态权限规则的声明式管理,若权限规则动态变化(如基于数据源),建议将注解与自定义PermissionResolver结合,掌握以上5个案例,你已能应对90%的权限校验场景,最后提醒:不要将注解放在@Transactional内部方法上,否则代理顺序可能导致事务提前提交。

抱歉,评论功能暂时关闭!