本文聚焦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):
| 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、服务名、用户角色)灵活实现。



