Pre和Post过滤器
通过Zuul Pre 过滤器做参数校验
/*** 参数校验 校验过来的请求是否都带了tocken* Created By 白* 2019/1/2410:34*/
@Component
public class TockienFilter extends ZuulFilter {@Overridepublic String filterType() {return PRE_TYPE;}@Overridepublic int filterOrder() {return PRE_DECORATION_FILTER_ORDER - 1;}@Overridepublic boolean shouldFilter() {return true;}@Overridepublic Object run() throws ZuulException {RequestContext requestContext=RequestContext.getCurrentContext();HttpServletRequest request=requestContext.getRequest();//从url参数获取 也可以从cookie,header获取String token=request.getParameter("token");if (StringUtils.isEmpty(token)){requestContext.setSendZuulResponse(false);requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());}return null;}
}
它们各自的含义与功能总结如下:
filterType:该函数需要返回一个字符串来代表过滤器的类型,而这个类型就是在HTTP请求过程中定义的各个阶段。在Zuul中默认定义了四种不同生命周期的过滤器类型,具体如下:
pre:可以在请求被路由之前调用。
routing:在路由请求时候被调用。
post:在routing和error过滤器之后被调用,也就是请求调用后。
error:处理请求时发生错误时被调用。
filterOrder:通过int值来定义过滤器的执行顺序,数值越小优先级越高。
shouldFilter:返回一个boolean类型来判断该过滤器是否要执行。我们可以通过此方法来指定过滤器的有效范围。
run:过滤器的具体逻辑。在该函数中,我们可以实现自定义的过滤逻辑,来确定是否要拦截当前的请求,不对其进行后续的路由,或是在请求路由返回结果之后,对处理结果做一些加工等。
此时通过Zuul访问其他服务的接口必须带token否则返回401
通过Zuul Post 过滤器给返回结果的Header添加信息
/*** 在返回的header中添加东西* Created By 白鹏* 2019/1/2411:00*/
@Component
public class addResponseHeaderFilter extends ZuulFilter {@Overridepublic String filterType() {return POST_TYPE;}@Overridepublic int filterOrder() {return SEND_RESPONSE_FILTER_ORDER -1;}@Overridepublic boolean shouldFilter() {return true;}@Overridepublic Object run() throws ZuulException {RequestContext requestContext=RequestContext.getCurrentContext();HttpServletResponse response=requestContext.getResponse();response.setHeader("X-Foo", UUID.randomUUID().toString());return null;}
}
限流
所有的请求都经过Zuul,所以可以通过限流来防止网络攻击
时机:请求被转发之前调用
令牌桶限流:首先根据一定速率给令牌桶放令牌,当满了就丢弃掉。当请求过来,那么先获取令牌,获取到令牌的就放行,获取不到的就拒绝。
@Component
public class RateLimitFilter extends ZuulFilter {//创建google令牌桶限流组件,每隔一秒放100个令牌private static final RateLimiter RATE_LIMITER=RateLimiter.create(100);@Overridepublic String filterType() {return PRE_TYPE;}@Overridepublic int filterOrder() {return SERVLET_DETECTION_FILTER_ORDER - 1;}@Overridepublic boolean shouldFilter() {return true;}@Overridepublic Object run() throws ZuulException {//去取令牌 如果没有取到 那么抛个异常if (!RATE_LIMITER.tryAcquire()){throw new RateLimitException();}return null;}
}
鉴权
首先在登陆方 放一个标识
卖家登陆 Cookie放入token 同时放入 redis
/*** 卖家登陆* @param openId* @param response* @return*/@GetMapping("/seller")public ResultVO seller(@RequestParam("openId")String openId, HttpServletResponse response, HttpServletRequest request){//判断是否已经登陆Cookie cookie=CookieUtil.get(request,CookieConstant.TOKEN);if (cookie!=null &&StringUtils.isNotEmpty(stringRedisTemplate.opsForValue().get(String.format(RedisConstant.TOKEN_TEMPLATE.toString(),cookie.getValue())))){return ResultVOUtil.success();}//查询UserInfo info=userService.findByOpenId(openId);//判断信息是否为空if (info==null){return ResultVOUtil.error(ResultEnum.LOGIN_FAIL);}//判断角色if (!RoleEnom.seller.getCode().equals(info.getRole())){return ResultVOUtil.error(ResultEnum.ROLE_ERROR);}//写入redisString token= UUID.randomUUID().toString();Integer expire = CookieConstant.expire;stringRedisTemplate.opsForValue().set(String.format(RedisConstant.TOKEN_TEMPLATE.toString(),token),openId,expire, TimeUnit.SECONDS);//设置CookieCookieUtil.set(response, CookieConstant.TOKEN,token,CookieConstant.expire);return ResultVOUtil.success();}
卖家对某个接口进行拦截
@Component
public class AuthSellerFilter extends ZuulFilter {@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Overridepublic String filterType() {return PRE_TYPE;}@Overridepublic int filterOrder() {return PRE_DECORATION_FILTER_ORDER - 1;}@Overridepublic boolean shouldFilter() {RequestContext requestContext=RequestContext.getCurrentContext();HttpServletRequest request=requestContext.getRequest();if ("/order/order/finish".equals(request.getServletPath())) {return true;}return false;}@Overridepublic Object run() throws ZuulException {/*** /order/finish 只能卖家访问 (cookie里有token)*/RequestContext requestContext=RequestContext.getCurrentContext();HttpServletRequest request=requestContext.getRequest();Cookie cookie=CookieUtil.get(request,CookieConstant.TOKEN);if(cookie==null|| StringUtils.isEmpty(cookie.getValue())|| StringUtils.isEmpty(stringRedisTemplate.opsForValue().get(String.format(RedisConstant.TOKEN_TEMPLATE,cookie.getValue())))){requestContext.setSendZuulResponse(false);requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());}return null;}
}
跨域
@Configuration
public class CorsConfig {@Beanpublic CorsFilter corsFilter(){final UrlBasedCorsConfigurationSource source=new UrlBasedCorsConfigurationSource();final CorsConfiguration config=new CorsConfiguration();config.setAllowCredentials(true);config.setAllowedOrigins(Arrays.asList("*"));config.setAllowedHeaders(Arrays.asList("*"));config.setAllowedMethods(Arrays.asList("*"));config.setMaxAge(300L);source.registerCorsConfiguration("/**",config);return new CorsFilter(source);}
}