目录
b)在 订单微服务 中实现 RequestOriginParser 接口中的 parseOrigin 方法
2.2.2、实现 BlockExceptionHandler 接口
授权规则是对请求者的身份做一个判断,判断是否又权限来访问我.
这里大家肯定会想起 Spring Cloud Gateway 网关,也是所有请求都需要经过网关去身份认证,看你有没有权限访问我,这里为什么还要整一个授权规则呢?
可以这样想啊,所有请求经过网关路由到微服务,此时网关才能对请求者的身份做认证,但是如果你们公司出现了内鬼,把微服务的地址给泄露给不怀好意的人,那些哥们就可以绕过网关直接访问微服务,因此就需要 sentinel 的权限股则解决这个问题.
Sentinel 的授权规则就可以验证你的请求是从哪里来的,如果是从网关来的,就让你走,如果是其他地方来的,就进行拦截.
在 Sentinel 的控制台中,选择权限规则就可以添加规则.

在 Sentinel 中有一个接口叫做 RequestOriginParser,通过他的方法叫 parseOrigin 就可以解析出请求者的来源. 只不过可惜的是,这个方法返回的结果永远是 default ,因此无法区分你是网关来的,还是浏览器来的,所以我们需要自己来实现这个接口.
具体的,我们只需要让网关来的请求和从浏览器来的请求的请求头信息不一样,然后实现 RequestOriginParser 接口的时候,在方法中进行一个判断就可以了.
利用网关过滤器,添加名字为 gateway 的 origin 头.
- spring:
- cloud:
- gateway:
- default-filters:
- - AddRequestHeader=origin,gateway # 添加名为origin的请求头,值为gateway
- @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 注解,交给容器去管理.

从浏览器中访问,就会被拦截.
Ps:这里我在网关中对以下资源放行通过

因此通过网关访问就不会被拦截

默认情况下,发生限流、降级、授权拦截都会抛出异常到调用方. 而默认的异常返回结果上面的案例也看到了,直接返回给用户不得懵逼了,因此我们可以自定义返回异常的结果.
我们只需要实现 BlockExceptionHandler 接口. 因为这个接口中就是用来处理上述所有异常的 .
- public interface BlockExceptionHandler {
-
- /**
- * 处理请求被限流、降级、授权拦截时抛出的异常:BlockException
- */
- void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception;
-
- }
BlockException 包含很多子类,分别对应以下场景:
实现 BlockExceptionHandler 接口自定义返回异常结果时,就可以针对 BlockException 的不类型,返回对应的不同结果.
在 订单服务 中,实现 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 注解
这里通过 授权规则 中的案例进行测试.
可以看到,不通过 网关,而通过浏览器直接访问就会触发自定义结果异常.

