shiro细粒度资源访问控制

测试智商的网站 6小时前 阅读数 3163 #在线测试

细粒度资源访问控制是 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 可以轻松实现细粒度资源访问控制。关键点包括:

shiro细粒度资源访问控制

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

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

  • 随机文章
  • 热门文章
  • 热评文章
热门