怎么配置 Apache Shiro 实现 RESTful API 的权限注解鉴权?

文章导读
配置 Apache Shiro 实现 RESTful API 权限注解鉴权,核心是通过自定义 Realm 加载权限数据,并在 Spring 环境中启用 AOP 支持注解解析。适用场景为基于 Spring Boot 的 Java Web 项目,风险边界在于 AJAX 请求默认会跳转登录页,需自定义过滤器返回 JSON 状态码。
📋 目录
  1. 快速处理思路
  2. 为什么会这样
  3. 分步处理
  4. 怎么验证是否生效
  5. 常见坑
  6. 常见问题
  7. 参考来源
A A

配置 Apache Shiro 实现 RESTful API 权限注解鉴权,核心是通过自定义 Realm 加载权限数据,并在 Spring 环境中启用 AOP 支持注解解析。适用场景为基于 Spring Boot 的 Java Web 项目,风险边界在于 AJAX 请求默认会跳转登录页,需自定义过滤器返回 JSON 状态码。

先说结论:Shiro 注解鉴权依赖 Spring AOP 代理,必须配置 SecurityManager 和 Realm,且需处理 RESTful 接口的非页面跳转响应。

  • 适合:Spring Boot 或 Spring MVC 架构的后台接口权限控制。
  • 先准备:引入 shiro-spring 依赖,编写继承 AuthorizingRealm 的自定义类。
  • 验收:无权限访问接口时,确认返回 401 或 403 状态码而非 HTML 登录页。

快速处理思路

Shiro 配置不涉及命令行操作,需按依赖、Realm、过滤器、AOP 四个环节检查。首先确认 pom 文件包含 shiro-spring 依赖,其次检查自定义 Realm 的 doGetAuthorizationInfo 方法是否返回了正确的权限字符串集合。接着配置 ShiroFilterFactoryBean 定义过滤链,最后确保 Spring 开启了注解代理支持。若接口是 AJAX 请求,需重写 PermissionsAuthorizationFilter 的 onAccessDenied 方法,避免默认重定向。

为什么会这样

注解鉴权失效通常是因为 Spring AOP 未代理受保护的 Bean,或者 Realm 未正确加载权限数据。Shiro 的注解如@RequiresPermissions 本质是切面,需要在 Spring 容器中生成代理对象才能拦截方法调用。权限数据存储在 Realm 中,若 doGetAuthorizationInfo 返回空集合,授权器 Authorizer 会判定无权限。RESTful 接口不同于传统 Web 页面,默认过滤器链配置 authc 或 perms 在未通过时会触发 redirect,导致前端接收不到 JSON 错误信息。

分步处理

第一步:引入依赖并配置 SecurityManager。在 Maven 项目中添加 shiro-spring 依赖,版本可参考 1.4.0 或更高稳定版。创建配置类定义 DefaultWebSecurityManager Bean,并注入自定义 Realm。

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.4.0</version>
</dependency>

第二步:实现自定义 Realm 加载权限。继承 AuthorizingRealm,重写 doGetAuthorizationInfo 方法。从数据库查询当前用户的角色和权限标识,存入 SimpleAuthorizationInfo 对象。权限字符串格式建议采用 资源:操作,如 user:list。

@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    String username = principals.getPrimaryPrincipal().toString();
    Set<String> roleid = userBiz.RoleidByUsername(username);
    Set<String> perid = userBiz.PeridByUsername(username);
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    info.setStringPermissions(perid);
    info.setRoles(roleid);
    return info;
}

第三步:配置过滤器链与注解支持。在 ShiroFilterFactoryBean 中设置 filterChainDefinitionMap,放行登录接口,保护业务接口。同时配置 AuthorizationAttributeSourceAdvisor 开启注解鉴权。

怎么配置 Apache Shiro 实现 RESTful API 的权限注解鉴权?
Map<String, String> filterChain = new LinkedHashMap<>();
filterChain.put("/login", "anon");
filterChain.put("/api/**", "authc");
shiroFilter.setFilterChainDefinitionMap(filterChain);

第四步:处理 RESTful 响应异常。创建自定义过滤器继承 PermissionsAuthorizationFilter,重写 onAccessDenied 方法。判断请求头是否包含 application/json,若是则设置响应状态为 401 或 403 并返回 JSON,否则执行默认重定向。

怎么验证是否生效

使用 Postman 或 curl 工具发送携带 Token 的请求访问受保护接口。首先测试无权限账号,确认返回 HTTP 403 Forbidden 且 body 为 JSON 格式错误信息。其次测试有权限账号,确认返回 HTTP 200 及业务数据。检查后端日志,确认 CustomRealm 的 doGetAuthorizationInfo 方法被调用且打印出正确的权限集合。

常见坑

第一个坑是注解不生效,原因是目标类未被 Spring 管理或未开启 AOP 代理,需在配置类添加@EnableAspectJAutoProxy 或配置 Advisor。第二个坑是 AJAX 请求被重定向到登录页,原因是未自定义过滤器处理 onAccessDenied,导致前端无法解析 HTML 跳转。第三个坑是权限字符串不匹配,Shiro 默认使用 PermissionResolver 进行字符串匹配,需确保代码中的注解值与数据库存储值完全一致,包括大小写和分隔符。

常见问题

Shiro 注解和 Spring Security 注解有什么区别?

Shiro 注解如@RequiresPermissions 是独立于 Spring 环境的,但整合 Spring 时需借助 AOP 实现。Spring Security 注解强依赖 Spring 容器,配置更复杂但功能更细。Shiro 适合中小型项目或需脱离 Spring 环境运行的场景。

RESTful 风格中 GET 和 POST 权限如何区分?

可以在过滤器链中配置 rest 过滤器,如/api/user=rest[user],Shiro 会根据 HTTP 动词自动映射权限。也可以在注解中指定具体权限字符串,如@RequiresPermissions("user:create") 对应 POST 请求。

自定义 Realm 中权限数据缓存吗?

默认情况下 Shiro 会缓存授权信息,若数据库权限变更需手动清除缓存。可在 Realm 中配置 CacheManager,或在权限修改后调用 Subject.logout 强制重新加载。

参考来源

  • CSDN 博客 - Shiro 权限与注解开发,消息于 2022 年 8 月 26 日发布
  • 博客园 - Shiro 拓展之 Restful URL 鉴权,发布时间是 2018 年 11 月 18 日
  • CSDN 博客 - Apache Shiro 详解:权限认证与授权实践,2022 年 4 月 7 日
  • 博客园 - Shiro 权限管理框架 (一):Shiro 的基本使用,截至 2021 年 8 月 19 日