Spring Shiro基础组件 Permission

相关阅读

简介

权限表示执行操作或者访问资源的能力,是系统安全策略中最细粒度或原子性的单元,是构建细粒度安全模型的基石;

核心方法

/**
 * 是否包含指定的权限
 */
boolean implies(Permission p);

实现子类

public interface Permission
    public class AllPermission implements Permission, Serializable
    public class WildcardPermission implements Permission, Serializable
        public class DomainPermission extends WildcardPermission

AllPermission

简介

全权限,包含所有的权限;

核心方法

/**
 * 是否包含指定的权限
 */
public boolean implies(Permission p) {
    // 总是返回true,表示拥有所有的权限
    return true;
}

WildcardPermission

简介

实现了一种非常灵活的权限结构,支持多级权限匹配;
格式:domain:action:instance,各部分可多值,可使用通配符"*”,",”分隔;
例如:group,user:create,delete:*表示对任意的group/user的实例拥有创建/删除的权限;

核心方法

// 通配符
protected static final String WILDCARD_TOKEN = "*";
// 各部分分隔符
protected static final String PART_DIVIDER_TOKEN = ":;
// 各子部分分隔符
protected static final String SUBPART_DIVIDER_TOKEN = ",;
// 不区分大小写
protected static final boolean DEFAULT_CASE_SENSITIVE = false;
// 权限结构
private List<Set<String>> parts;

/**
 * 构造函数
 */
public WildcardPermission(String wildcardString) {
    // 默认大小写不敏感
    this(wildcardString, DEFAULT_CASE_SENSITIVE);
}

/**
 * 设置权限结构
 */
protected void setParts(String wildcardString, boolean caseSensitive) {
    // 去除首尾空格
    wildcardString = StringUtils.clean(wildcardString);
    // 校验数据
    if (wildcardString == null || wildcardString.isEmpty()) {
        throw new IllegalArgumentException("Wildcard string cannot be null or empty. Make sure permission strings are properly formatted.");
    }

    // 大小写不敏感则统一小写化处理
    if (!caseSensitive) {
        wildcardString = wildcardString.toLowerCase();
    }

    // 分隔各部分内容
    List<String> parts = CollectionUtils.asList(wildcardString.split(PART_DIVIDER_TOKEN));

    // 解析权限结构
    this.parts = new ArrayList<Set<String>>();
    for (String part : parts) {
        // 分隔子部分内容
        Set<String> subparts = CollectionUtils.asSet(part.split(SUBPART_DIVIDER_TOKEN));

        // 校验子部分内容
        if (subparts.isEmpty()) {
            throw new IllegalArgumentException("Wildcard string cannot contain parts with only dividers. Make sure permission strings are properly formatted.");
        } 
        // 保存该部分内容
        this.parts.add(subparts);
    }

    // 校验权限结构
    if (this.parts.isEmpty()) {
        throw new IllegalArgumentException("Wildcard string cannot contain only dividers. Make sure permission strings are properly formatted.");
    }
}

/**
 * 是否包含指定权限
 */
public boolean implies(Permission p) {
    // 只支持和WildcardPermission比较
    // By default only supports comparisons with other WildcardPermissions
    if (!(p instanceof WildcardPermission)) {
        return false;
    }

    WildcardPermission wp = (WildcardPermission) p;

    List<Set<String>> otherParts = wp.getParts();

    int i = 0;
    // 遍历权限结构各部分
    for (Set<String> otherPart : otherParts) {
        // 如果本权限的权限结构的层级小于待比较的权限,则自动包含
        // If this permission has less parts than the other permission, everything after the number of parts contained
        // in this permission is automatically implied, so return true
        if (getParts().size() - 1 < i) {
            return true;
        } else {
            Set<String> part = getParts().get(i);
            if (!part.contains(WILDCARD_TOKEN) && !part.containsAll(otherPart)) {
                // 如果本部分不包含通配符,且没有包含待比较权限的所有子部分,则认为不包含
                return false;
            }
            i++;
        }
    }

    // 如果本权限的权限结构的层级大于待比较的权限,则剩余的部分必须都包含通配符才认为包含待比较权限
    // If this permission has more parts than the other parts, only imply it if all of the other parts are wildcards
    for (; i < getParts().size(); i++) {
        Set<String> part = getParts().get(i);
        if (!part.contains(WILDCARD_TOKEN)) {
            // 只要有一个不包含通配符,则认为不包含
            return false;
        }
    }

    return true;
}

DomainPermission

简介

提供方便类型安全/特定领域的子类可以扩展的基础类;
将权限部分分为:domain、actions、targets;

核心方法

// 领域
private String domain;
// 动作集合
private Set<String> actions;
// 实例集合
private Set<String> targets;

/**
 * 构造函数
 */
public DomainPermission(String actions, String targets) {
    // 根据类名得到领域名称
    this.domain = getDomain(getClass());
    this.actions = StringUtils.splitToSet(actions, SUBPART_DIVIDER_TOKEN);
    this.targets = StringUtils.splitToSet(targets, SUBPART_DIVIDER_TOKEN);
    encodeParts(this.domain, actions, targets);
}

/**
 * 根据类名得到领域名称
 */
protected String getDomain(Class<? extends DomainPermission> clazz) {
    String domain = clazz.getSimpleName().toLowerCase();
    //strip any trailing 'permission' text from the name (as all subclasses should have been named):
    int index = domain.lastIndexOf("permission");
    if (index != -1) {
        domain = domain.substring(0, index);
    }
    return domain;
}

/**
 * 设置权限结构
 */
protected void setParts(String domain, Set<String> actions, Set<String> targets) {
    String actionsString = StringUtils.toDelimitedString(actions, SUBPART_DIVIDER_TOKEN);
    String targetsString = StringUtils.toDelimitedString(targets, SUBPART_DIVIDER_TOKEN);
    encodeParts(domain, actionsString, targetsString);
    this.domain = domain;
    this.actions = actions;
    this.targets = targets;
}

/**
 * 设置权限结构
 */
private void encodeParts(String domain, String actions, String targets) {
    if (!StringUtils.hasText(domain)) {
        throw new IllegalArgumentException("domain argument cannot be null or empty.");
    }
    StringBuilder sb = new StringBuilder(domain);

    if (!StringUtils.hasText(actions)) {
        if (StringUtils.hasText(targets)) {
            // 无动作有实例时,则动作描述为通配符
            // 既无动作也无实例时,则只存在领域
            sb.append(PART_DIVIDER_TOKEN).append(WILDCARD_TOKEN);
        }
    } else {
        // 有动作则拼接动作信息
        sb.append(PART_DIVIDER_TOKEN).append(actions);
    }
    if (StringUtils.hasText(targets)) {
        // 有实例则拼接实例信息
        sb.append(PART_DIVIDER_TOKEN).append(targets);
    }
    // 调用父类方法设置权限结构
    setParts(sb.toString());
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值