alibaba / alibaba/Sentinel

[BUG] 系统规则与授权规则不生效

Open
#3,214 2 comments 0 reactions 0 assignees View on GitHub
kind/question
Dominant language
Java
Stars
23.1k
Forks
8.1k
PR merge metrics
No merged PRs in 30d

Description

## Issue Description

Type: *bug report*

### Describe what happened
基于毕业版本的SpringCloudAlibaba+SpringCloud+SpringBoot下配置并使用Sentinel的系统规则与授权规则不生效。

三个基础版本如图所示:
![image](https://github.com/alibaba/Sentinel/assets/39307424/19be882a-22ee-400b-b4f1-a459d83294ef)
Sentinel相关依赖如图所示:
![image](https://github.com/alibaba/Sentinel/assets/39307424/4ca5ea59-6c73-43c1-a555-9cf26bbe75a1)
定义测试用的Controller类:
`package com.nriet.cipas.controller.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.nriet.cipas.common.util.exception.ExceptionUtils;
import com.nriet.cipas.environment.annotation.NotControllerResponseAdvice;
import com.nriet.cipas.service.service.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

@RestController
@Slf4j
public class UserController {
@Autowired
private IUserService userService;

@GetMapping("/user/getUserByName")
@SentinelResource(value = "/user/getUserByName",blockHandler = "blockHandlerGetUserByName")
public String getUserByName(@RequestParam("userName") String userName){
return userService.selectUserByName(userName);
}

public String blockHandlerGetUserByName(String userName, BlockException ex)
{
ExceptionUtils.extracted(ex);
return "";
}

@GetMapping("/user/{userId}")
@SentinelResource(value = "/user/userId",blockHandler = "blockHandler")
public String userId(@PathVariable("userId") String userId){
return "checked!";
}

public String blockHandler(String userId, BlockException ex)
{
ExceptionUtils.extracted(ex);
return "";
}

@GetMapping("/user/authority")
@SentinelResource(value = "/user/authority",blockHandler = "blockHandlerAuthority")
public String authority(@RequestParam("userId") String userId){
return "passed!";
}

public String blockHandlerAuthority(String userId, BlockException ex)
{
ExceptionUtils.extracted(ex);
return "";
}
}
`

其他方法1:
`package com.nriet.cipas.common.util.exception;

import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;

public class ExceptionUtils {

public static void extracted(BlockException ex) {
if(ex instanceof FlowException) {
throw new ApplicationDefinedException(ExceptionEnum.SENTINEL_FLOW_ERROR.getCode(), "selectUserByName" + "方法被限流了,请稍后重试");
} else if (ex instanceof DegradeException) {
throw new ApplicationDefinedException(ExceptionEnum.SENTINEL_DEGRADE_ERROR.getCode(), "selectUserByName" + "方法被降级熔断了,请稍后重试");
} else if (ex instanceof ParamFlowException) {
throw new ApplicationDefinedException(ExceptionEnum.SENTINEL_PARAMS_ERROR.getCode(), "selectUserByName" + "方法触发热点参数限流,请稍后重试");
} else if (ex instanceof AuthorityException) {
throw new ApplicationDefinedException(ExceptionEnum.SENTINEL_AUTH_ERROR.getCode(), "selectUserByName" + "方法访问权限不足,请联系服务管理员");
} else if (ex instanceof SystemBlockException) {
throw new ApplicationDefinedException(ExceptionEnum.SENTINEL_SYSTEM_BLOCK_ERROR.getCode(), "selectUserByName" + "方法触发系统保护了,请稍后重试");
}
}
}
`

全局异常处理类:
`package com.nriet.cipas.environment.exception;

import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import com.nriet.cipas.common.util.exception.ApplicationDefinedException;
import com.nriet.cipas.common.util.exception.ExceptionEnum;
import com.nriet.cipas.instance.vo.result.ResultVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.util.List;
import java.util.stream.Collectors;

@ControllerAdvice
@ResponseBody //统一在类前面加上@ResponseBody注解,这样在方法上就不需要添加了,返回的数据都是json格式的
public class GlobalExceptionAdvice {
private Logger logger = LoggerFactory.getLogger(GlobalExceptionAdvice.class);

/**
* 使用form data方式调用接口,校验异常抛出 BindException
* @param e
* @return
*/
@ExceptionHandler({BindException.class})
public ResultVO BindExceptionHandler(BindException e) {
List fieldErrors = e.getBindingResult().getFieldErrors();
List collect = fieldErrors.stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage)
.collect(Collectors.toList());
logger.error(getMsg(e));
return new ResultVO<>(ExceptionEnum.ARGUMENT_ERROR.getCode(),ExceptionEnum.ARGUMENT_ERROR.getMsg() , collect.toString());
}

/**
* 处理参数校验异常。使用 json 请求体调用接口,校验异常抛出 MethodArgumentNotValidException
* 调用/globalExceptionTest/addUser接口测试。
* 传入:
* {"account":"222sada99999999999","password":"3","email":"a519991925"}
* 报错为:
* {
* "code": 108,
* "message": "参数不合法",
* "data": "[用户id不能为空, 邮箱格式不正确, 密码长度必须是6-16个字符, 账号长度必须是6-11个字符]"
* }
* @param e
* @return
*/
@ExceptionHandler({MethodArgumentNotValidException.class})
public ResultVO MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
// 从异常对象中拿到ObjectError对象
List fieldErrors = e.getBindingResult().getFieldErrors();
List collect = fieldErrors.stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage)
.collect(Collectors.toList());
logger.error(getMsg(e));
logger.error(collect.toString());
return new ResultVO<>(ExceptionEnum.ARGUMENT_ERROR.getCode(),ExceptionEnum.ARGUMENT_ERROR.getMsg() , collect);
}

/**
* 处理业务自定义异常
* @param e
* @return
*/
@ExceptionHandler(value = ApplicationDefinedException.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public ResultVO ApplicationDefinedExceptionHandler(ApplicationDefinedException e){
logger.error(getMsg(e));
return new ResultVO<>(e.getCode(),e.getMessage(),null);
}

@ExceptionHandler(value = FlowException.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public ResultVO flowExceptionHandler(FlowException e){
logger.error(getMsg(e));
return new ResultVO<>(ExceptionEnum.SENTINEL_FLOW_ERROR.getCode(),ExceptionEnum.SENTINEL_FLOW_ERROR.getMsg(),null);
}

@ExceptionHandler(value = DegradeException.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public ResultVO degradeExceptionHandler(DegradeException e){
logger.error(getMsg(e));
return new ResultVO<>(ExceptionEnum.SENTINEL_DEGRADE_ERROR.getCode(),ExceptionEnum.SENTINEL_DEGRADE_ERROR.getMsg(),null);
}

@ExceptionHandler(value = ParamFlowException.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public ResultVO paramFlowException(ParamFlowException e){
logger.error(getMsg(e));
return new ResultVO<>(ExceptionEnum.SENTINEL_PARAMS_ERROR.getCode(),ExceptionEnum.SENTINEL_PARAMS_ERROR.getMsg(),null);
}

@ExceptionHandler(value = AuthorityException.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public ResultVO authorityExceptionHandler(AuthorityException e){
logger.error(getMsg(e));
return new ResultVO<>(ExceptionEnum.SENTINEL_AUTH_ERROR.getCode(),ExceptionEnum.SENTINEL_AUTH_ERROR.getMsg(),null);
}

@ExceptionHandler(value = SystemBlockException.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public ResultVO systemBlockExceptionHandler(SystemBlockException e){
logger.error(getMsg(e));
return new ResultVO<>(ExceptionEnum.SENTINEL_SYSTEM_BLOCK_ERROR.getCode(),ExceptionEnum.SENTINEL_SYSTEM_BLOCK_ERROR.getMsg(),null);
}

/**
* 处理其它异常
* @param e
* @return
*/
@ExceptionHandler(value = Exception.class)
//ResponseStatus没有必要了,因为我们在全局异常处理类中已经设置了,这里统一用200即可
// @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public ResultVO exceptionHandler(Exception e){
logger.error(getMsg(e));
return new ResultVO<>(ExceptionEnum.UNKNOW_ERROR.getCode(),ExceptionEnum.UNKNOW_ERROR.getMsg(),null);
}

private static String getMsg(Exception e) {
StackTraceElement[] stackTrace = e.getStackTrace();
StringBuffer sb = new StringBuffer();
sb.append(e.toString()).append("\r\n");
for (StackTraceElement stackTraceElement : stackTrace) {
sb.append("\tat ").append(stackTraceElement.getClassName()).append(".")
.append(stackTraceElement.getMethodName())
.append("(").append(stackTraceElement.getFileName()).append(":").append(stackTraceElement.getLineNumber())
.append(")\r\n");
}
return sb.toString();
}
}
`

origin解析类:
`package com.nriet.cipas.environment.configuration;

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

import javax.servlet.http.HttpServletRequest;

@Component
public class RequestOriginParserDefinition implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest httpServletRequest) {
// 当前 流控应用 放在了请求参数里面,可以放到的地方有很多,比如 参数/请求头/session/等等
return httpServletRequest.getParameter("sourceName");
}
}
`

bootstrap.properties相关Sentinel配置:
`#sentinel
spring.cloud.sentinel.transport.dashboard=localhost:8885
spring.cloud.sentinel.transport.clientIp=${spring.cloud.client.ip-address}
spring.cloud.sentinel.transport.port=18719
spring.cloud.sentinel.web-context-unify=false
spring.cloud.sentinel.eager=true

spring.cloud.sentinel.datasource.flow.nacos.server-addr=${spring.cloud.nacos.config.server-addr}
spring.cloud.sentinel.datasource.flow.nacos.namespace=${spring.cloud.nacos.config.namespace}
spring.cloud.sentinel.datasource.flow.nacos.username=${spring.cloud.nacos.config.username}
spring.cloud.sentinel.datasource.flow.nacos.password=${spring.cloud.nacos.config.password}
spring.cloud.sentinel.datasource.flow.nacos.data-id=${spring.application.name}-flow-rules
spring.cloud.sentinel.datasource.flow.nacos.groupId=SENTINEL_GROUP
spring.cloud.sentinel.datasource.flow.nacos.data-type=json
spring.cloud.sentinel.datasource.flow.nacos.rule-type=flow

spring.cloud.sentinel.datasource.degrade.nacos.server-addr=${spring.cloud.nacos.config.server-addr}
spring.cloud.sentinel.datasource.degrade.nacos.namespace=${spring.cloud.nacos.config.namespace}
spring.cloud.sentinel.datasource.degrade.nacos.username=${spring.cloud.nacos.config.username}
spring.cloud.sentinel.datasource.degrade.nacos.password=${spring.cloud.nacos.config.password}
spring.cloud.sentinel.datasource.degrade.nacos.data-id=${spring.application.name}-degrade-rules
spring.cloud.sentinel.datasource.degrade.nacos.groupId=SENTINEL_GROUP
spring.cloud.sentinel.datasource.degrade.nacos.data-type=json
spring.cloud.sentinel.datasource.degrade.nacos.rule-type=degrade
#
spring.cloud.sentinel.datasource.system.nacos.server-addr=${spring.cloud.nacos.config.server-addr}
spring.cloud.sentinel.datasource.system.nacos.namespace=${spring.cloud.nacos.config.namespace}
spring.cloud.sentinel.datasource.system.nacos.username=${spring.cloud.nacos.config.username}
spring.cloud.sentinel.datasource.system.nacos.password=${spring.cloud.nacos.config.password}
spring.cloud.sentinel.datasource.system.nacos.data-id=${spring.application.name}-system-rules
spring.cloud.sentinel.datasource.system.nacos.groupId=SENTINEL_GROUP
spring.cloud.sentinel.datasource.system.nacos.data-type=json
spring.cloud.sentinel.datasource.system.nacos.rule-type=system
#
spring.cloud.sentinel.datasource.authority.nacos.server-addr=${spring.cloud.nacos.config.server-addr}
spring.cloud.sentinel.datasource.authority.nacos.namespace=${spring.cloud.nacos.config.namespace}
spring.cloud.sentinel.datasource.authority.nacos.username=${spring.cloud.nacos.config.username}
spring.cloud.sentinel.datasource.authority.nacos.password=${spring.cloud.nacos.config.password}
spring.cloud.sentinel.datasource.authority.nacos.data-id=${spring.application.name}-authority-rules
spring.cloud.sentinel.datasource.authority.nacos.groupId=SENTINEL_GROUP
spring.cloud.sentinel.datasource.authority.nacos.data-type=json
spring.cloud.sentinel.datasource.authority.nacos.rule-type=authority
#
spring.cloud.sentinel.datasource.param-flow.nacos.server-addr=${spring.cloud.nacos.config.server-addr}
spring.cloud.sentinel.datasource.param-flow.nacos.namespace=${spring.cloud.nacos.config.namespace}
spring.cloud.sentinel.datasource.param-flow.nacos.username=${spring.cloud.nacos.config.username}
spring.cloud.sentinel.datasource.param-flow.nacos.password=${spring.cloud.nacos.config.password}
spring.cloud.sentinel.datasource.param-flow.nacos.data-id=${spring.application.name}-param-flow-rules
spring.cloud.sentinel.datasource.param-flow.nacos.groupId=SENTINEL_GROUP
spring.cloud.sentinel.datasource.param-flow.nacos.data-type=json
spring.cloud.sentinel.datasource.param-flow.nacos.rule-type=param-flow`

Sentinel-dashboard版本为1.8.0,可以读取、新增、修改、删除该应用程序所有配置。
![image](https://github.com/alibaba/Sentinel/assets/39307424/161e0105-5468-4bcc-b62e-c91d2876d40c)

应用服务启动正常,相关测试接口测试正常(包括限流、降级、热点三个规则,都能正常使用)
![image](https://github.com/alibaba/Sentinel/assets/39307424/ad1f04b1-d5ac-43bb-b9a8-81387d932d4c)

### Describe what you expected to happen
无论通过手动修改Nacos上的关于系统规则与授权规则的配置文件、还是通过Dashboard修改,都无法生效。
![image](https://github.com/alibaba/Sentinel/assets/39307424/cbdfefed-248d-4cd0-8afc-9e948850ff79)
![image](https://github.com/alibaba/Sentinel/assets/39307424/a8302dd9-6996-4bc2-b8f7-96512646ae0b)

例如以20并发调用测试接口,检验系统规则在并发数为3的生效情况,shiji实际并未触发:
![image](https://github.com/alibaba/Sentinel/assets/39307424/b4026d64-3867-446c-8b9b-4a8674109dc9)
![image](https://github.com/alibaba/Sentinel/assets/39307424/5a239c2f-ec92-449f-8f4e-5dfb7aff24a9)
![image](https://github.com/alibaba/Sentinel/assets/39307424/a19f07c5-b29a-497f-bf46-b64da59cb819)

例如配置授权规则,以白名单方式强制限定仅有“cipas-example2”的应用才能调用测试接口,也无法生效。
![image](https://github.com/alibaba/Sentinel/assets/39307424/0d7727cf-b813-4b10-8f3b-1d7cb7e955fd)
![image](https://github.com/alibaba/Sentinel/assets/39307424/11acd542-bbfe-4299-a9af-8e0a28b52a00)

请问该如何处理这种问题?

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.