详解SpringCloud Zuul过滤器返回值拦截

作者:cmlbeliever 时间:2023-02-05 07:59:37 

Zuul作为网关服务,是其他各服务对外中转站,通过Zuul进行请求转发。这就涉及到部分数据是不能原封返回的,比如服务之间通信的凭证,用户的加密信息等等。

举个例子,用户服务提供一个登录接口,用户名密码正确后返回一个Token,此Token作为用户服务的通行证,那么用户登录成功后返回的Token就需要进行加密或者防止篡改处理。在到达用户服务其他接口前,就需要对Token进行校验,非法的Token就不需要转发到用户服务中了,直接在网关层返回信息即可。

要修改服务返回的信息,需要使用的是Zuul的过滤器。使用时只需要继承ZuulFilter,实现必要的方法即可。

Zuul提供默认的四种过滤器类型,通过filterType方法进行标识

  1. pre:可以在请求被路由之前调用

  2. route:在路由请求时候被调用

  3. post:在route和error过滤器之后被调用

  4. error:处理请求时发生错误时被调用

过滤器执行的顺序是通过filterOrder方法进行排序,越小的值越优先处理。FilterConstants定义了一些列默认的过滤器的执行顺序和路由类型,大部分需要用到的常量都在这儿。

例子中说明的,只有登录接口需要拦截,所以只需要拦截登录请求(/user/login)即可。可以通过过滤器的shouldFilter方法进行判断是否需要拦截。

由于是在准发用户服务成功后进行的数据修改,所以 * 的类型时post类型的。整个类的实现如下:


public class AuthResponseFilter extends AbstractZuulFilter {

private static final String RESPONSE_KEY_TOKEN = "token";
@Value("${system.config.authFilter.authUrl}")
private String authUrl;
@Value("${system.config.authFilter.tokenKey}")
private String tokenKey = RESPONSE_KEY_TOKEN;

@Autowired
private AuthApi authApi;

@Override
public boolean shouldFilter() {
 RequestContext context = getCurrentContext();
 return StringUtils.equals(context.getRequest().getRequestURI().toString(), authUrl);
}

@Override
public Object run() {

try {
  RequestContext context = getCurrentContext();

InputStream stream = context.getResponseDataStream();
  String body = StreamUtils.copyToString(stream, Charset.forName("UTF-8"));

if (StringUtils.isNotBlank(body)) {
   Gson gson = new Gson();
   @SuppressWarnings("unchecked")
   Map<String, String> result = gson.fromJson(body, Map.class);
   if (StringUtils.isNotBlank(result.get(tokenKey))) {
    AuthModel authResult = authApi.encodeToken(result.get(tokenKey));
    if (authResult.getStatus() != HttpServletResponse.SC_OK) {
     throw new IllegalArgumentException(authResult.getErrMsg());
    }
    String accessToken = authResult.getToken();
    result.put(tokenKey, accessToken);
   }
   body = gson.toJson(result);
  }
  context.setResponseBody(body);
 } catch (IOException e) {
  rethrowRuntimeException(e);
 }
 return null;
}

@Override
public String filterType() {
 return FilterConstants.POST_TYPE;
}

@Override
public int filterOrder() {
 return FilterConstants.SEND_RESPONSE_FILTER_ORDER - 2;
}

}

配置文件,中添加授权url和返回token的key:

system.config.authFilter.authUrl=/user/login
system.config.authFilter.tokenKey=token

context.setResponseBody(body);这段代码是核心,通过此方法修改返回数据。

当用户登录成功后,根据返回的token,通过授权服务进行token加密,这里加密方式使用的是JWT。防止用户篡改信息,非法的请求直接可以拦截在网关层。

关于Zuul过滤器的执行过程,这里不需要多说明,源码一看便知,ZuulServletFilter:


@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
 try {
  init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);
  try {
   preRouting();
  } catch (ZuulException e) {
   error(e);
   postRouting();
   return;
  }

// Only forward onto to the chain if a zuul response is not being sent
  if (!RequestContext.getCurrentContext().sendZuulResponse()) {
   filterChain.doFilter(servletRequest, servletResponse);
   return;
  }

try {
   routing();
  } catch (ZuulException e) {
   error(e);
   postRouting();
   return;
  }
  try {
   postRouting();
  } catch (ZuulException e) {
   error(e);
   return;
  }
 } catch (Throwable e) {
  error(new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_FROM_FILTER_" + e.getClass().getName()));
 } finally {
  RequestContext.getCurrentContext().unset();
 }
}

方法说明:

  1. preRoute:执行pre类型的过滤器

  2. postRoute:执行post类型的过滤器

  3. route:执行route类型的过滤器

  4. error:执行error类型的过滤器

通过context.setSendZuulResponse(false)可以终止请求的转发,但是只在pre类型的过滤器中设置才可以。

关于如何终止过滤器:

只有pre类型的过滤器支持终止转发,其他过滤器都是按照顺序执行的,而且pre类型的过滤器也只有在所有pre过滤器执行完后才可以终止转发,做不到终止过滤器继续执行。看ZuulServletFilter源码代码:


 // Only forward onto to the chain if a zuul response is not being sent
  if (!RequestContext.getCurrentContext().sendZuulResponse()) {
   filterChain.doFilter(servletRequest, servletResponse);
   return;
  }

本文中的代码已提交至: https://gitee.com/cmlbeliever/springcloud 欢迎Star

实现类在:api-getway工程下的com.cml.springcloud.api.filter.AuthResponseFilter

本地地址:http://xz.jb51.net:81/201806/yuanma/cmlbeliever-springcloud_jb51.rar

来源:https://blog.csdn.net/cml_blog/article/details/78349703

标签:Spring,Cloud,Zuul,过滤器
0
投稿

猜你喜欢

  • JavaWeb详细讲述Cookie和Session的概念

    2022-03-23 08:39:44
  • JAVA实现的简单万年历代码

    2021-10-02 21:35:34
  • Spring Cloud微服务架构Sentinel数据双向同步

    2021-07-16 04:17:04
  • 基于mybatis逆向工程的使用步骤详解

    2022-10-28 09:27:26
  • C语言编程中统计输入的行数以及单词个数的方法

    2021-06-08 10:49:31
  • C#中+=是什么意思及+=的用法

    2023-07-11 23:25:31
  • Android实现H5与Native交互的两种方式

    2023-01-01 05:35:42
  • 零基础学习教程之Linux下搭建android开发环境

    2021-12-08 02:13:24
  • 如何使用正则表达式判断邮箱(以C#为例)

    2022-12-09 21:38:30
  • Android 消息机制以及handler的内存泄露

    2023-08-01 07:59:44
  • C#清除WebBrowser中Cookie缓存的方法

    2022-01-13 20:01:08
  • Java JDK 1.8 lambda的用法详解

    2022-01-15 04:09:48
  • dotnet core链接mongodb代码实例

    2023-07-20 14:26:09
  • Android实现缓存大图到SD卡

    2022-07-13 07:13:50
  • 人工智能开发语言排行榜: 不死Java, 不朽C/C++, 新贵Python【推荐】

    2023-03-12 16:06:54
  • java多线程加锁以及Condition类的使用实例解析

    2023-08-07 07:25:30
  • 深入C# 内存管理以及优化的方法详解

    2021-10-24 14:24:03
  • 为什么阿里要慎重使用ArrayList中的subList方法

    2023-12-07 19:03:34
  • Android UI控件Switch的使用方法

    2023-01-28 13:41:15
  • 详解C#读取Appconfig中自定义的节点

    2022-07-16 08:30:38
  • asp之家 软件编程 m.aspxhome.com