目录
b)在 订单微服务 中实现 RequestOriginParser 接口中的 parseOrigin 方法
2.2.2、实现 BlockExceptionHandler 接口
一、授权规则
1.1、什么是授权规则
授权规则是对请求者的身份做一个判断,判断是否又权限来访问我.
这里大家肯定会想起 Spring Cloud Gateway 网关,也是所有请求都需要经过网关去身份认证,看你有没有权限访问我,这里为什么还要整一个授权规则呢?
可以这样想啊,所有请求经过网关路由到微服务,此时网关才能对请求者的身份做认证,但是如果你们公司出现了内鬼,把微服务的地址给泄露给不怀好意的人,那些哥们就可以绕过网关直接访问微服务,因此就需要 sentinel 的权限股则解决这个问题.
Sentinel 的授权规则就可以验证你的请求是从哪里来的,如果是从网关来的,就让你走,如果是其他地方来的,就进行拦截.
1.2、授权规则的配置
1.2.1、配置信息介绍
在 Sentinel 的控制台中,选择权限规则就可以添加规则.
- 资源名:就是之前提到的“资源”,比如 /order/{orderId}.
- 流控应用:填写调用者的名字.
- 授权类型:白名单就是允许通过的名单,黑名单就想相反了. 比如你想要调用者允许从网关进来,那么流控应用就填写 “gateway”(这里需要配置,后面会讲),然后选择白名单即可.
1.2.2、如何得到请求来源
在 Sentinel 中有一个接口叫做 RequestOriginParser,通过他的方法叫 parseOrigin 就可以解析出请求者的来源. 只不过可惜的是,这个方法返回的结果永远是 default ,因此无法区分你是网关来的,还是浏览器来的,所以我们需要自己来实现这个接口.
具体的,我们只需要让网关来的请求和从浏览器来的请求的请求头信息不一样,然后实现 RequestOriginParser 接口的时候,在方法中进行一个判断就可以了.
1.2.3、实现步骤
a)给网关过来的请求添加请求头信息
利用网关过滤器,添加名字为 gateway 的 origin 头.
spring:
cloud:
gateway:
default-filters:
- AddRequestHeader=origin,gateway # 添加名为origin的请求头,值为gateway
b)在 订单微服务 中实现 RequestOriginParser 接口中的 parseOrigin 方法
@Component
public class HeaderOriginParser implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest httpServletRequest) {
String origin = httpServletRequest.getHeader("origin");
if(StringUtils.isEmpty(origin)) {
return "blank";
}
return origin;
}
}
Ps:要加上 Component 注解,交给容器去管理.
c)在 Sentinel 控制台中添加授权规则
d)测试分析
从浏览器中访问,就会被拦截.
Ps:这里我在网关中对以下资源放行通过
因此通过网关访问就不会被拦截
二、自定义异常结果
2.1、用处
默认情况下,发生限流、降级、授权拦截都会抛出异常到调用方. 而默认的异常返回结果上面的案例也看到了,直接返回给用户不得懵逼了,因此我们可以自定义返回异常的结果.
我们只需要实现 BlockExceptionHandler 接口. 因为这个接口中就是用来处理上述所有异常的 .
public interface BlockExceptionHandler {
/**
* 处理请求被限流、降级、授权拦截时抛出的异常:BlockException
*/
void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception;
}
2.2、具体实现
2.2.1、自定义异常结果种类
BlockException 包含很多子类,分别对应以下场景:
- FlowException:限流异常.
- ParamFlowException:热点参数限流的异常
- DegradeException:降级异常.
- AuthorityException:授权规则异常.
- SystemBlockException:系统规则异常.
实现 BlockExceptionHandler 接口自定义返回异常结果时,就可以针对 BlockException 的不类型,返回对应的不同结果.
2.2.2、实现 BlockExceptionHandler 接口
在 订单服务 中,实现 BlockExceptionHandler 接口.
@Component
public class SentinelBlockHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
String msg = "未知异常";
int status = 429;
if(e instanceof FlowException) {
msg = "请求被限流了!";
} else if(e instanceof DegradeException) {
msg = "请求被降级了!";
} else if(e instanceof ParamFlowException) {
msg = "热点参数限流!";
} else if(e instanceof AuthorityException) {
msg = "请求没有权限!";
status = 401;
}
httpServletResponse.setContentType("application/json;charset=utf-8");
httpServletResponse.setStatus(status);
httpServletResponse.getWriter().println("{message:"+msg+", status:"+status+"}");
}
}
Ps:不要忘了 Component 注解
2.2.3、分析结果
这里通过 授权规则 中的案例进行测试.
可以看到,不通过 网关,而通过浏览器直接访问就会触发自定义结果异常.