Source access control (black and white lists)
concept
Sentinel provides the function of black and white lists to restrict the passage of resources. If a whitelist is configured, only requests corresponding to request sources in the whitelist can pass; if a blacklist is configured, requests corresponding to request sources in the blacklist cannot pass.
Actual operation
In the configuration management/configuration list of the Nacos console, create the following configuration in the public namespace:
dataId:spring-cloud-demo-provider-sentinel-authority
group:DEFAULT_GROUP
The configuration content is as follows:
[
{
"resource": "/hello",
"limitApp": "white-origin",
"strategy": 0
},
{
"resource": "/hello/say",
"limitApp": "black-origin",
"strategy": 1
}
]
If strategy is 0, it means white list; if it is 1, it means black list.
limitApp If there are multiple request sources, separate them with commas.
The corresponding client configuration file is as follows:
spring:
application:
name: spring-cloud-demo-provider
cloud:
nacos:
discovery:
server-addr: 10.211.55.11:8848,10.211.55.12:8848,10.211.55.13:8848
enabled: true
sentinel:
transport:
dashboard: 127.0.0.1:9000
eager: true
web-context-unify: false
datasource:
authority-nacos-datasource:
nacos:
server-addr: 10.211.55.11:8848,10.211.55.12:8848,10.211.55.13:8848
group-id: DEFAULT_GROUP
namespace: public
data-id: ${
spring.application.name}-sentinel-authority
data-type: json
rule-type: authority
username: nacos
password: nacos
Then register a Bean of type RequestOriginParser.
@Component
public class MyRequestOriginParser implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest httpServletRequest) {
String origin = httpServletRequest.getHeader("origin");
if (StringUtils.isBlank(origin)) {
origin = "default";
}
return origin;
}
}
When requesting, add a pair of origin, whiteOrigin or origin, blackOrigin to the request header to see the restriction effect of the black and white lists on specific resources.
In actual operation, I personally found that if restricted by the black and white list, the program will not throw an exception, but output Blocked by Sentinel (flow limiting) in the response.
AuthoritySlot
Responsible for verifying the authorization rules of the request source.
@Spi(order = Constants.ORDER_AUTHORITY_SLOT)
public class AuthoritySlot extends AbstractLinkedProcessorSlot<DefaultNode> {
@Override
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, boolean prioritized, Object... args)
throws Throwable {
// 校验请求来源的授权规则
checkBlackWhiteAuthority(resourceWrapper, context);
// 交给下一个ProcessorSlot继续处理
fireEntry(context, resourceWrapper, node, count, prioritized, args);
}
@Override
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
// 交给下一个ProcessorSlot继续处理
fireExit(context, resourceWrapper, count, args);
}
void checkBlackWhiteAuthority(ResourceWrapper resource, Context context) throws AuthorityException {
// 加载所有资源的授权规则
Map<String, Set<AuthorityRule>> authorityRules = AuthorityRuleManager.getAuthorityRules();
// 如果授权规则列表为空,则直接返回
if (authorityRules == null) {
return;
}
// 获取指定资源的授权规则列表
Set<AuthorityRule> rules = authorityRules.get(resource.getName());
// 如果对应的授权规则列表为空,则直接返回
if (rules == null) {
return;
}
// 遍历授权规则列表
for (AuthorityRule rule : rules) {
// 如果有一个授权规则没有校验通过,则抛出异常
if (!AuthorityRuleChecker.passCheck(rule, context)) {
throw new AuthorityException(context.getOrigin(), rule);
}
}
}
}
Next, look at the internal logic of the passCheck method of AuthorityRuleChecker.
static boolean passCheck(AuthorityRule rule, Context context) {
// 获取上下文记录的请求来源
String requester = context.getOrigin();
// 如果请求来源为空或者授权规则的limitApp为空,则返回true,表示校验通过
if (StringUtil.isEmpty(requester) || StringUtil.isEmpty(rule.getLimitApp())) {
return true;
}
// 判断授权规则的limitApp中是否存在指定的请求来源
int pos = rule.getLimitApp().indexOf(requester);
boolean contain = pos > -1;
if (contain) {
boolean exactlyMatch = false;
// 用逗号分隔
String[] appArray = rule.getLimitApp().split(",");
// 判断授权规则中是否对指定的请求来源进行了限制
for (String app : appArray) {
if (requester.equals(app)) {
exactlyMatch = true;
break;
}
}
contain = exactlyMatch;
}
int strategy = rule.getStrategy();
// 如果设置了黑名单,并且授权规则中包含指定的请求来源,则返回false,表示校验不通过
if (strategy == RuleConstant.AUTHORITY_BLACK && contain) {
return false;
}
// 如果设置了白名单,并且授权规则中不包含指定的请求来源,则返回false,表示校验不通过
if (strategy == RuleConstant.AUTHORITY_WHITE && !contain) {
return false;
}
// 其余请求,返回true,表示校验通过
return true;
}