欢迎光临
我们一直在努力

授权规则:黑白名单 + 来源控制实战

本文聚焦Sentinel授权规则的核心实战:黑白名单控制与来源控制。作为微服务架构中接口安全防护的关键手段,授权规则能帮我们精准拦截非法访问、规范接口调用来源,是保障服务稳定性和安全性的重要屏障。

本文全程实战导向,从“理论铺垫→环境准备→分步实操→进阶优化→避坑指南”,覆盖新手入门到生产落地的全流程,所有代码可直接复制复用,建议收藏后跟着实操,确保学完就能上手!

一、前置认知:为什么需要授权规则?

在微服务场景中,我们经常会遇到这样的需求:

  • 核心接口(如用户信息修改、订单删除)仅允许公司内网IP访问,禁止外部公网调用;

  • 某个接口被恶意IP频繁请求,需要拉黑该IP,阻止其继续访问;

  • 微服务间调用时,仅允许指定服务(如网关、订单服务)调用当前服务接口,防止内部非法调用;

  • 后台管理接口,仅允许管理员来源的请求访问,普通用户无法触发。

这些需求,都可以通过Sentinel的授权规则来实现。Sentinel授权规则的核心逻辑是:基于请求的“来源”(origin),通过黑白名单策略,控制请求是否能访问目标资源,本质是一种“访问权限校验”机制。

1.1 核心概念拆解

在开始实操前,先明确3个核心概念,避免后续踩坑:

  • 资源(Resource):Sentinel保护的对象,也是授权规则作用的目标,通常是接口URL、接口方法名(如/user/get、orderCreate),是限流、授权的最小粒度。

  • 来源(Origin):请求的发起者标识,可理解为“谁在调用接口”,常见的来源有:IP地址、服务名、用户角色(如admin、guest)、设备类型等。Sentinel默认不会自动识别来源,需要我们自定义解析逻辑。

  • 黑白名单策略:

    • 白名单(AUTHORITY_WHITE):仅允许来源在白名单内的请求访问资源,相当于“放行名单”;

    • 黑名单(AUTHORITY_BLACK):禁止来源在黑名单内的请求访问资源,相当于“拦截名单”。

  • 1.2 授权规则核心原理

    Sentinel通过AuthoritySlot(授权插槽)实现授权规则的校验,它是Sentinel处理链中的重要一环,核心流程如下:

  • 请求进入Sentinel保护的资源时,AuthoritySlot被触发;

  • 通过自定义的来源解析器,获取当前请求的来源(origin);

  • AuthorityRuleManager加载该资源对应的授权规则,交给AuthorityRuleChecker进行校验;

  • 根据黑白名单策略和来源匹配结果,决定放行或拦截请求(拦截时抛出AuthorityException)。

  • 关键注意点:每个资源只能配置一条授权规则,无法为同一个接口同时配置“拉黑A”和“只允许B”两条规则,需合并为一条规则(如将A加入黑名单、B加入白名单,或合并为单一策略)。

    二、环境准备(必做)

    本次实战基于SpringBoot + SpringCloud Alibaba + Sentinel,提前准备好以下环境,避免实操时卡顿:

    2.1 依赖配置(Maven)

    核心依赖包括Sentinel核心包、SpringCloud Alibaba Sentinel适配器,若需要规则持久化,可添加Nacos数据源依赖(生产环境推荐):

    <!– SpringBoot 基础依赖(略) –>

    <!– SpringCloud Alibaba Sentinel 核心依赖 –>
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2021.0.4.0</version> <!– 版本与SpringCloud Alibaba对应 –>
    </dependency>

    <!– SpringBoot Actuator(可选,用于监控) –>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

    <!– Sentinel Nacos 规则持久化依赖(生产环境推荐,可选) –>
    <dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
    </dependency>

    <!– OpenFeign(微服务调用场景,可选) –>
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>

    2.2 配置文件(application.yml)

    配置Sentinel控制台地址、服务名、来源解析相关配置,以及可选的Nacos持久化配置:

    spring:
    application:
    name: sentinel–authority–demo # 服务名,控制台显示用
    cloud:
    alibaba:
    sentinel:
    transport:
    dashboard: 127.0.0.1:8858 # Sentinel控制台地址(自行部署)
    port: 8719 # 与控制台通信端口,默认8719,占用则自动+1
    eager: true # 饥饿加载,避免首次调用无规则
    web-context-unify: false # 关闭web上下文统一,便于自定义来源解析
    # 可选:Nacos规则持久化配置(生产环境必配,避免重启服务丢失规则)
    datasource:
    authority-rule: # 授权规则数据源
    nacos:
    server-addr: 127.0.0.1:8848 # Nacos地址
    data-id: ${spring.application.name}–authority–rules
    group-id: SENTINEL_GROUP
    rule-type: authority # 规则类型:授权规则

    # 暴露监控端点(可选)
    management:
    endpoints:
    web:
    exposure:
    include: '*'

    # 日志配置(可选,便于排查授权失败问题)
    logging:
    level:
    com.alibaba.csp.sentinel: INFO

    2.3 控制台部署

    Sentinel控制台是可视化配置授权规则的核心工具,部署方式简单(Windows/Linux通用):

  • 下载Sentinel控制台jar包(推荐版本1.8.6,与依赖兼容):Sentinel官方下载地址;

  • 执行命令启动控制台:java -jar sentinel-dashboard-1.8.6.jar –server.port=8858(端口可自定义,避免冲突);

  • 访问控制台:http://127.0.0.1:8858,默认账号密码:sentinel/sentinel;

  • 启动本地SpringBoot服务,控制台会自动注册该服务(首次调用接口后,服务会出现在控制台列表中)。

  • 三、实战一:IP黑白名单控制(最常用)

    IP黑白名单是最基础的授权场景,适用于“限制特定IP访问”,比如拉黑恶意IP、仅允许内网IP访问核心接口。本次实战实现两个场景:

    场景1:拉黑恶意IP(192.168.1.100、192.168.1.101),禁止其访问所有接口;

    场景2:仅允许内网IP(127.0.0.1、192.168.1.0/24网段)访问核心接口(/user/admin)。

    3.1 步骤1:自定义IP来源解析器

    Sentinel默认不会自动获取请求的IP作为来源,需要实现RequestOriginParser接口,自定义来源解析逻辑(将请求的IP作为origin):

    package com.example.sentinelauthoritydemo.config;

    import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
    import org.springframework.stereotype.Component;

    import javax.servlet.http.HttpServletRequest;
    import java.util.Objects;

    /**
    * 自定义IP来源解析器(用于Sentinel IP黑白名单授权)
    */

    @Component
    public class IpRequestOriginParser implements RequestOriginParser {

    @Override
    public String parseOrigin(HttpServletRequest request) {
    // 1. 获取请求的IP地址(处理代理场景,如Nginx、网关转发)
    String ip = request.getHeader("X-Forwarded-For");
    if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
    ip = request.getHeader("Proxy-Client-IP");
    }
    if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
    ip = request.getHeader("WL-Proxy-Client-IP");
    }
    if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
    ip = request.getRemoteAddr();
    }
    // 2. 处理多IP转发场景(X-Forwarded-For可能包含多个IP,取第一个)
    if (ip != null && ip.contains(",")) {
    ip = ip.split(",")[0].trim();
    }
    // 3. 兜底:若未获取到IP,标记为unknown
    return Objects.requireNonNullElse(ip, "unknown");
    }
    }

    说明:该解析器会将请求的真实IP作为来源(origin),适配网关转发、代理等生产场景,避免因代理导致IP获取错误。

    3.2 步骤2:编写测试接口

    编写两个测试接口,用于验证IP黑白名单效果:

    package com.example.sentinelauthoritydemo.controller;

    import com.alibaba.csp.sentinel.annotation.SentinelResource;
    import com.alibaba.csp.sentinel.slots.block.BlockException;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;

    /**
    * 测试接口:用于验证Sentinel授权规则(IP黑白名单)
    */

    @RestController
    @RequestMapping("/user")
    public class UserController {

    /**
    * 普通接口:所有人可访问(除了黑名单IP)
    */

    @GetMapping("/public")
    @SentinelResource(value = "userPublic", blockHandler = "blockHandler")
    public String publicInterface() {
    return "普通接口:当前IP已通过Sentinel授权校验,访问成功!";
    }

    /**
    * 核心接口:仅允许内网IP访问(白名单)
    */

    @GetMapping("/admin")
    @SentinelResource(value = "userAdmin", blockHandler = "blockHandler")
    public String adminInterface() {
    return "核心接口:当前IP在白名单内,访问成功!";
    }

    /**
    * 授权失败兜底方法(必须与被保护方法参数一致,且最后多一个BlockException参数)
    */

    public String blockHandler(BlockException e) {
    // 可根据异常类型区分:授权失败、限流、熔断等
    return "授权失败:当前IP无访问权限!异常信息:" + e.getMessage();
    }
    }

    关键说明:@SentinelResource注解用于标记被Sentinel保护的资源,value是资源名(后续配置授权规则时需对应),blockHandler是授权失败的兜底方法。

    3.3 步骤3:控制台配置IP黑白名单规则

    启动SpringBoot服务和Sentinel控制台,访问一次测试接口(如http://127.0.0.1:8080/user/public),确保服务在控制台注册成功,然后配置授权规则:

    3.3.1 配置黑名单规则(拦截恶意IP)
  • 控制台左侧选择「授权规则」→ 点击「新增授权规则」;

  • 配置核心参数(重点对应资源名和IP):

    • 资源名:userPublic(与接口上@SentinelResource的value一致);

    • 授权类型:IP(默认,可下拉选择);

    • 策略:黑名单;

    • 配置值:192.168.1.100,192.168.1.101(多个IP用逗号分隔);

    • 备注:拉黑恶意IP,禁止访问普通接口。

  • 点击「新增」,规则实时生效(无需重启服务)。

  • 3.3.2 配置白名单规则(仅允许内网IP访问核心接口)
  • 再次点击「新增授权规则」;

  • 配置核心参数:

    • 资源名:userAdmin(与核心接口的资源名一致);

    • 授权类型:IP;

    • 策略:白名单;

    • 配置值:127.0.0.1,192.168.1.0/24(支持网段配置,/24表示该网段下所有IP);

    • 备注:仅允许内网IP访问核心接口。

  • 点击「新增」,规则生效。

  • 3.4 步骤4:测试验证

    使用Postman或浏览器,模拟不同IP访问接口,验证规则效果(可通过修改本地hosts或使用代理工具切换IP):

    访问IP访问接口预期结果实际结果
    192.168.1.100(黑名单) /user/public 授权失败 授权失败:当前IP无访问权限
    127.0.0.1(白名单) /user/admin 访问成功 核心接口:当前IP在白名单内,访问成功!
    10.0.0.1(非白名单) /user/admin 授权失败 授权失败:当前IP无访问权限
    192.168.1.102(非黑名单) /user/public 访问成功 普通接口:当前IP已通过Sentinel授权校验,访问成功!

    测试通过后,说明IP黑白名单规则配置生效,实现了预期的授权控制效果。

    四、实战二:服务来源控制(微服务场景)

    在微服务架构中,服务间调用频繁,我们需要限制“只有指定服务才能调用当前服务的接口”,避免非法服务调用。比如:订单服务(order-service)只能被网关服务(gateway-service)和用户服务(user-service)调用,其他服务禁止调用。

    本次实战基于OpenFeign实现微服务调用,重点演示“服务来源控制”的全流程。

    4.1 步骤1:自定义服务来源解析器

    服务来源控制的核心是“识别调用方的服务名”,我们通过请求头携带服务名,再自定义解析器获取服务名作为origin:

    package com.example.sentinelauthoritydemo.config;

    import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
    import org.springframework.stereotype.Component;

    import javax.servlet.http.HttpServletRequest;
    import java.util.Objects;

    /**
    * 自定义服务来源解析器(用于微服务间授权)
    * 从请求头中获取调用方服务名,作为Sentinel的origin
    */

    @Component
    public class ServiceRequestOriginParser implements RequestOriginParser {

    // 定义请求头中携带服务名的key(自定义,调用方需对应)
    private static final String SERVICE_NAME_HEADER = "Service-Name";

    @Override
    public String parseOrigin(HttpServletRequest request) {
    // 从请求头中获取调用方服务名
    String serviceName = request.getHeader(SERVICE_NAME_HEADER);
    // 兜底:未获取到服务名,标记为unknown(会被拦截)
    return Objects.requireNonNullElse(serviceName, "unknown");
    }
    }

    说明:若同时需要IP和服务来源控制,可在解析器中返回“IP:服务名”的格式(如127.0.0.1:gateway-service),后续配置规则时对应即可。

    4.2 步骤2:配置调用方(微服务调用时携带服务名)

    以OpenFeign调用为例,在调用方(如gateway-service)的Feign接口中,添加请求头,携带自身服务名:

    package com.example.gatewayservice.feign;

    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestHeader;

    /**
    * 调用sentinel-authority-demo服务的Feign接口
    */

    @FeignClient(name = "sentinel-authority-demo") // 被调用服务名
    public interface UserFeignClient {

    // 调用被保护的接口,在请求头中携带自身服务名
    @GetMapping("/user/admin")
    String getAdminInfo(@RequestHeader("Service-Name") String serviceName);
    }

    调用方Controller层调用Feign接口时,传入自身服务名:

    @RestController
    @RequestMapping("/gateway")
    public class GatewayController {

    @Autowired
    private UserFeignClient userFeignClient;

    // 调用被保护接口,携带自身服务名(gateway-service)
    @GetMapping("/call-admin")
    public String callAdmin() {
    return userFeignClient.getAdminInfo("gateway-service");
    }
    }

    4.3 步骤3:控制台配置服务来源授权规则

    在Sentinel控制台,为被调用服务(sentinel-authority-demo)的核心接口配置服务来源白名单:

  • 左侧「授权规则」→「新增授权规则」;

  • 配置核心参数:

    • 资源名:userAdmin(与被保护接口的资源名一致);

    • 授权类型:自定义(下拉选择,对应服务名来源);

    • 策略:白名单;

    • 配置值:gateway-service,user-service(允许调用的服务名,多个用逗号分隔);

    • 备注:仅允许网关和用户服务调用核心接口。

  • 点击「新增」,规则生效。

  • 4.4 步骤4:测试验证

  • 合法调用(gateway-service调用):访问网关接口http://127.0.0.1:8081/gateway/call-admin,调用方携带服务名gateway-service,预期访问成功;

  • 合法调用(user-service调用):同理,user-service携带自身服务名调用,预期访问成功;

  • 非法调用(test-service调用):若test-service携带服务名test-service调用,预期授权失败,返回兜底提示;

  • 无服务名调用:若调用方未携带Service-Name请求头,origin为unknown,预期授权失败。

  • 测试结果符合预期,说明服务来源控制规则配置成功,实现了微服务间的授权校验。

    五、进阶优化:生产环境落地技巧

    前面的实操的是基础场景,在生产环境中,还需要注意以下几点,避免规则失效或出现性能问题:

    5.1 规则持久化(必做)

    Sentinel控制台配置的规则默认存储在内存中,服务重启后规则会丢失,生产环境必须配置规则持久化,推荐使用Nacos作为数据源(前面配置文件已预留相关配置),步骤如下:

  • 登录Nacos控制台,新建配置:

    • 数据ID:sentinel-authority-demo-authority-rules(服务名 + authority-rules);

    • 分组:SENTINEL_GROUP;

    • 配置格式:JSON;

    • 配置内容(授权规则示例,与控制台配置一致):[ { "resource": "userPublic", "limitApp": "192.168.1.100,192.168.1.101", "strategy": 1, // 1=黑名单,0=白名单 "controlBehavior": 0, "clusterMode": false }, { "resource": "userAdmin", "limitApp": "gateway-service,user-service", "strategy": 0, // 0=白名单 "controlBehavior": 0, "clusterMode": false } ]

  • 保存配置后,服务重启时会自动从Nacos加载授权规则,控制台修改规则后也会同步到Nacos,实现规则持久化。

  • 5.2 性能优化

    授权规则的校验会伴随每一次请求,需注意以下优化点,避免影响接口性能:

    • 开启Sentinel饥饿加载(eager: true),避免首次调用时规则未加载,导致授权失效;

    • 简化来源解析器逻辑,避免在解析器中执行耗时操作(如数据库查询);

    • 批量配置规则,避免频繁更新规则(规则更新会触发全量加载);

    • 核心接口优先使用白名单(白名单校验逻辑更简洁,性能更优)。

    5.3 多场景组合授权

    实际场景中,可能需要“IP+服务名”双重授权,比如:仅允许内网IP的gateway-service调用核心接口,此时可修改来源解析器,返回“IP:服务名”格式,再配置白名单为“192.168.1.10:gateway-service”即可。

    六、常见坑点避坑指南(新手必看)

    结合实战经验,整理了4个新手最容易踩的坑,提前规避:

    坑点1:资源名不匹配,规则不生效

    问题:控制台配置的资源名,与接口@SentinelResource的value不一致,导致授权规则无效;

    解决:确保资源名完全一致(区分大小写),建议统一命名规范(如接口URL全路径、方法名)。

    坑点2:来源解析器未注册,origin为unknown

    问题:自定义了解析器,但未添加@Component注解,导致Sentinel无法获取origin,所有请求都被拦截;

    解决:给解析器添加@Component注解,确保Spring能扫描到并注入。

    坑点3:多个授权规则配置冲突

    问题:为同一个资源配置了多条授权规则,导致规则冲突(Sentinel仅生效最后一条);

    解决:每个资源只能配置一条授权规则,多条件需合并(如多个IP、多个服务名用逗号分隔)。

    坑点4:代理场景下IP获取错误

    问题:服务部署在Nginx或网关后面,解析器获取到的是代理IP,而非真实客户端IP;

    解决:在解析器中优先获取X-Forwarded-For请求头,处理多IP转发场景(前面的IP解析器已适配)。

    七、总结与拓展

    本文我们完成了Sentinel授权规则的核心实战:IP黑白名单控制和服务来源控制,掌握了“理论→配置→实操→优化”的全流程,重点总结:

  • 授权规则的核心是“来源(origin)+ 黑白名单策略”,通过AuthoritySlot实现校验;

  • IP黑白名单适用于单体服务、对外接口的安全防护,服务来源控制适用于微服务间调用;

  • 生产环境必须配置规则持久化(Nacos),避免规则丢失,同时注意性能优化;

  • 自定义来源解析器是关键,需根据实际场景(IP、服务名、用户角色)灵活实现。

  • 赞(0)
    未经允许不得转载:171主机测评 » 授权规则:黑白名单 + 来源控制实战
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址