Sentinel黑白名单授权控制详解

AuthoritySlotSentinel 中用于实现 黑白名单授权控制(Authority Control) 的核心组件。它通过拦截请求上下文中的 origin(调用来源),与配置的规则进行匹配,从而决定是否放行请求。

我们从整体架构出发,逐层拆解理解:


一、整体目标

根据请求来源(origin)是否在白名单或黑名单中,决定是否允许访问某个资源。

  • 白名单模式(AUTHORITY_WHITE):只有来自指定 origin 的请求才被允许。
  • 黑名单模式(AUTHORITY_BLACK):来自指定 origin 的请求被拒绝。

典型应用场景:

  • 微服务 A 只允许被 B 和 C 调用,拒绝其他服务;
  • 防止恶意调用方(如已知的攻击 IP 或服务名)访问敏感接口。

二、组件结构概览

职责
AuthoritySlot Sentinel 处理链中的一个插槽(ProcessorSlot),负责在请求进入时执行权限检查
AuthorityRuleManager 管理所有 AuthorityRule 规则的加载、更新、存储
AuthorityRuleChecker 核心判断逻辑:给定一条规则和当前上下文,是否通过
AuthorityRule 权限规则实体:包含资源名、限制应用(limitApp)、策略(黑白名单)

三、详细解析

1. AuthoritySlot ------ 拦截入口

java 复制代码
public void entry(...) throws Throwable {
    checkBlackWhiteAuthority(resourceWrapper, context);
    fireEntry(...); // 继续处理链
}
  • 在每次请求进入 Sentinel 保护的资源时,该 Slot 会被调用。
  • 调用 checkBlackWhiteAuthority 进行权限校验。
  • 如果校验失败(抛出 AuthorityException),后续逻辑不会执行(即请求被拒绝)。

✅ 这是典型的 责任链模式(Chain of Responsibility) 中的一环。


2. AuthorityRuleManager ------ 规则管理中心

关键点:
  • 使用 RuleManager<AuthorityRule> 存储规则,按 resource 名 分组。
  • 支持动态规则更新(通过 SentinelProperty + PropertyListener 机制)。
  • 提供 getRules(String resource) 方法,快速获取某资源的所有权限规则。
规则加载逻辑(loadAuthorityConf):
java 复制代码
for (AuthorityRule rule : list) {
    if (!isValidRule(rule)) continue;
    if (StringUtil.isBlank(rule.getLimitApp())) {
        rule.setLimitApp(RuleConstant.LIMIT_APP_DEFAULT); // 默认值 ""
    }

    String resource = rule.getResource();
    // 每个 resource 最多只保留一条 AuthorityRule!
    if (newRuleMap.containsKey(resource)) {
        warn("Ignoring redundant rule");
    } else {
        newRuleMap.put(resource, [rule]);
    }
}

⚠️ 重要限制每个资源只能有一条 AuthorityRule

这意味着你不能为同一个 API 同时配置"拒绝 A"和"只允许 B"------必须合并成一条规则(比如 limitApp="A,B" + 黑名单策略)。


3. AuthorityRuleChecker.passCheck() ------ 核心判断逻辑

java 复制代码
static boolean passCheck(AuthorityRule rule, Context context) {
    String requester = context.getOrigin(); // 调用方标识,如 "service-A"
    String limitApp = rule.getLimitApp();   // 配置的限制应用列表,如 "app1,app2"

    // origin 为空 或 limitApp 为空 → 放行(安全默认)
    if (isEmpty(requester) || isEmpty(limitApp)) {
        return true;
    }

    // 初步判断:limitApp 字符串是否包含 requester(子串匹配)
    boolean contain = limitApp.indexOf(requester) > -1;

    // 但必须是 **精确匹配**(按逗号分割后逐个比对)
    if (contain) {
        boolean exactlyMatch = false;
        for (String app : limitApp.split(",")) {
            if (requester.equals(app.trim())) { // 注意 trim()
                exactlyMatch = true;
                break;
            }
        }
        contain = exactlyMatch;
    }

    // 根据策略判断
    if (rule.getStrategy() == AUTHORITY_BLACK && contain) {
        return false; // 黑名单命中 → 拒绝
    }
    if (rule.getStrategy() == AUTHORITY_WHITE && !contain) {
        return false; // 白名单未命中 → 拒绝
    }

    return true;
}
举个例子:
场景 limitApp strategy origin 结果
白名单 "web,admin" WHITE "admin" ✅ 通过
白名单 "web,admin" WHITE "hacker" ❌ 拒绝
黑名单 "bad,bad2" BLACK "bad" ❌ 拒绝
黑名单 "bad,bad2" BLACK "good" ✅ 通过
origin 为空 任意 任意 "" ✅ 通过(安全宽松)

🔍 为什么先用 indexOf 再精确匹配?

是一种性能优化:先快速排除明显不包含的情况,再做 split 和遍历。


4. AuthorityRule ------ 规则定义

  • resource:受保护的资源名(如 "/api/order")
  • limitApp:逗号分隔的调用方列表(如 "service-a,service-b")
  • strategy
    • 0 = AUTHORITY_WHITE(白名单)
    • 1 = AUTHORITY_BLACK(黑名单)

📌 注意:limitApp 中的值必须与 Context.getOrigin() 返回的值完全一致(区分大小写、无空格)。


四、使用方式(如何生效?)

  1. 设置 origin

    在调用方,需通过 ContextUtil.enter(resourceName, origin) 设置 origin:

    java 复制代码
    ContextUtil.enter("my-resource", "payment-service");
  2. 配置 AuthorityRule

    java 复制代码
    AuthorityRule rule = new AuthorityRule()
        .setResource("my-resource")
        .setLimitApp("order-service,auth-service") // 允许这两个服务调用
        .setStrategy(RuleConstant.AUTHORITY_WHITE);
    
    AuthorityRuleManager.loadRules(Collections.singletonList(rule));
  3. 请求进入时自动校验

    Sentinel 的 AuthoritySlot 会在处理链中自动拦截并校验。


五、注意事项 & 最佳实践

优点

  • 简单高效,适合服务间调用鉴权;
  • 支持动态规则更新(无需重启);
  • 与 Sentinel 其他功能(流控、熔断)无缝集成。

⚠️ 限制/注意

  1. 每个资源仅支持一条 AuthorityRule → 设计时需合并规则。
  2. origin 必须由调用方显式设置,否则为空 → 自动放行(可能造成安全漏洞!)。
  3. 不适用于 HTTP Header/IP 级别控制 (那是网关/WAF 的事),这里控制的是 逻辑调用方身份(如微服务名)。
  4. limitApp 不支持通配符或正则(仅精确匹配)。

六、总结

这套机制实现了 基于调用方身份的访问控制,核心思想:

"谁(origin)可以访问什么资源(resource)?"

  • 通过 AuthoritySlot 插入处理链;
  • 通过 AuthorityRuleManager 管理规则;
  • 通过 AuthorityRuleChecker 执行黑白名单判断;
  • 规则粒度:每个资源一条规则,支持白名单或黑名单

非常适合 微服务内部调用鉴权 场景,是 Sentinel 实现"零信任"网络的一个轻量级手段。


如果你有具体使用问题(比如如何设置 origin、如何动态推送规则、为何规则没生效等),欢迎继续提问!

相关推荐
chaodaibing2 小时前
【Java】一个批量更新插入数据到MySQL的工具类
java·开发语言·mysql
在坚持一下我可没意见2 小时前
Spring 后端安全双剑(上篇):JWT 无状态认证 + 密码加盐加密实战
java·服务器·开发语言·spring boot·后端·安全·spring
lang201509282 小时前
Sentinel预热限流器深度解析
sentinel
就像风一样抓不住2 小时前
SpringBoot静态资源映射:如何让/files/路径访问服务器本地文件
java·spring boot·后端
小O的算法实验室2 小时前
2023年IEEE TIV,GA-LNS算法+直升机救援调度,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
缪懿2 小时前
javaEE:多线程,单列模式和生产者消费者模型
java·单例模式·java-ee
foundbug9992 小时前
Delta并联机器人正逆解实现
算法·机器人
启山智软2 小时前
【单体系统与分布式系统是两种根本不同的软件架构模式】
java·vue.js·spring boot·后端·spring