shiro细粒度资源访问控制

举报
林欣 发表于 2025/05/25 23:32:11 2025/05/25
【摘要】 细粒度资源访问控制是 Shiro 的核心功能之一,允许开发者基于资源实例(如数据库记录、文件路径等)和操作(如读取、编辑、删除)定义权限。以下是完整的实现步骤和示例代码: 1. 核心概念权限字符串格式:资源:操作(如 user:edit:123 表示编辑 ID 为 123 的用户)授权流程:通过 Subject.isPermitted("权限字符串") 动态判断权限。 2. 完整实现步骤 (...

细粒度资源访问控制是 Shiro 的核心功能之一,允许开发者基于资源实例(如数据库记录、文件路径等)和操作(如读取、编辑、删除)定义权限。以下是完整的实现步骤和示例代码:


1. 核心概念

  • 权限字符串格式资源:操作(如 user:edit:123 表示编辑 ID 为 123 的用户)
  • 授权流程:通过 Subject.isPermitted("权限字符串") 动态判断权限。

2. 完整实现步骤

(1) 自定义 Realm 实现权限校验
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import java.util.HashSet;
import java.util.Set;

public class PermissionRealm extends AuthorizingRealm {

    // 模拟数据库存储的用户角色和权限
    private static final Map<String, Set<String>> USER_ROLES = new HashMap<>();
    private static final Map<String, Set<String>> ROLE_PERMISSIONS = new HashMap<>();

    static {
        // 初始化角色和权限数据
        Set<String> adminPermissions = new HashSet<>();
        adminPermissions.add("user:create");
        adminPermissions.add("user:edit:123"); // 允许编辑ID为123的用户
        adminPermissions.add("user:delete");
        ROLE_PERMISSIONS.put("admin", adminPermissions);

        Set<String> userPermissions = new HashSet<>();
        userPermissions.add("user:view");
        ROLE_PERMISSIONS.put("user", userPermissions);

        USER_ROLES.put("admin", new HashSet<>(Collections.singletonList("admin")));
        USER_ROLES.put("user1", new HashSet<>(Arrays.asList("user", "guest")));
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // 模拟从数据库获取用户信息
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        String username = upToken.getUsername();
        if (!"admin".equals(username) && !"user1".equals(username)) {
            throw new UnknownAccountException("用户不存在");
        }
        return new SimpleAuthenticationInfo(username, "password", getName());
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = (String) principals.getPrimaryPrincipal();
        Set<String> roles = USER_ROLES.get(username);
        if (roles == null) {
            return null;
        }

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addRoles(roles);

        // 根据角色添加权限
        for (String role : roles) {
            Set<String> permissions = ROLE_PERMISSIONS.get(role);
            if (permissions != null) {
                info.addStringPermissions(permissions);
            }
        }
        return info;
    }
}

(2) 配置 Shiro 使用自定义 Realm

shiro.ini 配置文件

[main]
permissionRealm = com.example.PermissionRealm
securityManager.realms = $permissionRealm

(3) 测试细粒度权限校验
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;

public class PermissionDemo {
    public static void main(String[] args) {
        // 初始化 SecurityManager
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);

        // 获取当前用户
        Subject currentUser = SecurityUtils.getSubject();

        // 模拟用户登录
        currentUser.login(new org.apache.shiro.authc.UsernamePasswordToken("admin", "password"));

        // 测试细粒度权限
        System.out.println("是否有创建用户权限: " + currentUser.isPermitted("user:create")); // true
        System.out.println("是否有编辑ID为123的用户权限: " + currentUser.isPermitted("user:edit:123")); // true
        System.out.println("是否有删除用户权限: " + currentUser.isPermitted("user:delete")); // true
        System.out.println("是否有编辑ID为456的用户权限: " + currentUser.isPermitted("user:edit:456")); // false(未授权)

        // 模拟普通用户登录
        currentUser.logout();
        currentUser.login(new org.apache.shiro.authc.UsernamePasswordToken("user1", "password"));
        System.out.println("普通用户是否有编辑权限: " + currentUser.isPermitted("user:edit:123")); // false
    }
}

3. 关键点说明

  1. 权限字符串设计

    • user:create:全局用户创建权限。
    • user:edit:123:仅允许编辑 ID 为 123 的用户,实现实例级控制。
  2. 动态权限校验

    • 通过 Subject.isPermitted("权限字符串") 动态判断,无需硬编码权限逻辑。
  3. 扩展性

    • 可从数据库加载权限数据,支持动态权限变更。

4. 输出结果

运行 PermissionDemo 的输出:

是否有创建用户权限: true
是否有编辑ID123的用户权限: true
是否有删除用户权限: true
是否有编辑ID456的用户权限: false
普通用户是否有编辑权限: false

总结

通过自定义 Realm 和权限字符串设计,Shiro 可以轻松实现细粒度资源访问控制。关键点包括:

  1. 权限字符串格式化:用 资源:操作:实例 定义权限。
  2. 动态校验:通过 Subject.isPermitted() 实时判断权限。
  3. 数据驱动:权限数据可从数据库动态加载,适应复杂业务场景。

这种设计既灵活又安全,适用于企业级应用中的权限管理需求。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。