下面是一个完整的示例,演示如何使用Zuul的过滤器来实现请求的验签功能。
验签逻辑
我们假设需要对所有请求进行验签,验签的逻辑如下:
- 获取请求参数中的
sign
和timestamp
参数。 - 将所有请求参数按照参数名字母升序排列,将参数值进行拼接。
- 将拼接后的字符串加上
app_secret
,然后使用MD5
进行加密。 - 将加密后的结果和请求参数中的
sign
进行比较,如果相等则验签通过,否则验签失败。
实现过滤器
我们需要在pre
类型的过滤器中实现验签逻辑。具体实现如下:
public class SignCheckFilter extends ZuulFilter {
private static final String SIGN_PARAM_NAME = "sign";
private static final String TIMESTAMP_PARAM_NAME = "timestamp";
private static final String APP_SECRET = "my_secret";
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String sign = request.getParameter(SIGN_PARAM_NAME);
String timestamp = request.getParameter(TIMESTAMP_PARAM_NAME);
Map<String, String[]> paramMap = request.getParameterMap();
if (StringUtils.isEmpty(sign) || StringUtils.isEmpty(timestamp)) {
ctx.setSendZuulResponse(false);
ctx.setResponseBody("Sign or timestamp is empty.");
ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
return null;
}
String paramStr = paramMap.keySet().stream()
.sorted()
.filter(key -> !SIGN_PARAM_NAME.equals(key))
.map(key -> key "=" request.getParameter(key))
.collect(Collectors.joining("&"));
String expectedSign = DigestUtils.md5Hex(paramStr APP_SECRET);
if (!expectedSign.equals(sign)) {
ctx.setSendZuulResponse(false);
ctx.setResponseBody("Sign is invalid.");
ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
return null;
}
return null;
}
}
在上述代码中,我们首先定义了SIGN_PARAM_NAME
、TIMESTAMP_PARAM_NAME
和APP_SECRET
三个常量,分别表示验签参数名称、时间戳参数名称和密钥。
然后在run
方法中,我们获取请求中的sign
和timestamp
参数,以及所有的请求参数。接下来,我们将所有的请求参数按照参数名字母升序排列,将参数值进行拼接,然后将拼接后的字符串加上APP_SECRET
,使用MD5
进行加密,得到期望的sign
值。最后,我们将期望的sign
值和请求中的sign
进行比较,如果相等则验签通过,否则验签失败。
如果验签失败,我们会在run
方法中设置SendZuulResponse
为false
,表示不继续执行后面的路由和后置过滤器,直接返回响应给客户端。我们还设置了响应状态码和响应体,让客户端知道验签失败的原因。
过滤器注册
最后一步是将自定义的过滤器注册到Zuul中。我们可以在Spring Boot应用的配置文件中添加以下配置:
代码语言:javascript复制zuul:
routes:
api:
path: /api/**
url: http://localhost:8081/
filters:
pre:
signCheckFilter:
enabled: true
在上述配置中,我们首先定义了一个路由规则,将所有以/api
开头的请求转发到http://localhost:8081/
。然后我们定义了一个名为signCheckFilter
的过滤器,并将其设置为pre
类型的过滤器,并将其启用。这样,每个进入Zuul的请求都会经过我们自定义的过滤器进行验签。