Spring Cloud Zuul自定义Filter

/ Spring Cloud / 没有评论 / 44浏览

介绍Spring Cloud Zuul如何自定义Filter。

场景

我们希望能对请求过滤,例如访问api接口需要权限,这个时候我们自定义Filter就派上用场了。

如何自定义Filter

继承com.netflix.zuul.ZuulFilter

/**
 * 自定义网关过滤器
 *
 * Created by xuan on 2018/3/26
 */
public class AccessFilter extends ZuulFilter {

    private static final Logger LOG = LoggerFactory.getLogger(AccessFilter.class);

    private static final int FILTER_ORDER = 0;

    private static final String HEADER_AUTHORIZATION = "Authorization";
    private static final String HEADER_AUTHORIZATION_USER = "Authorization-User";
    private static final String API = "/*/api/**";

    private final PathMatcher matcher = new AntPathMatcher();

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

    @Override
    public int filterOrder() {
        return FILTER_ORDER;
    }

    @Override
    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        // 对于/serviceId/api/**需要token才能访问微服务
        return matcher.match(API, request.getRequestURI());
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        String jwtToken = request.getHeader(HEADER_AUTHORIZATION);
        if(StringUtils.isBlank(jwtToken)) {
            LOG.debug("access token is empty");
            sendJwtError(ctx);
            return null;
        }
        // 解析token
        Claims claims;
        try {
            claims = JwtUtil.parse(jwtToken);
        } catch (Exception e) {
            LOG.warn("parse jwt exception: {}", e.getMessage(), e);
            sendJwtError(ctx);
            return null;
        }
        // 将用户信息传递给具体的微服务
        addUserContext(ctx, claims);
        return null;
    }

    private void sendJwtError(RequestContext ctx) {
        ctx.setSendZuulResponse(false);
        ctx.setResponseStatusCode(401);
        ctx.setResponseBody("token invalid");
    }

    private void addUserContext(RequestContext ctx, Claims claims) {
        String username = claims.get("username", String.class);
        // todo redis中获取到用户信息
        // todo 将用户信息通过request header传递到微服务
        ctx.addZuulRequestHeader(HEADER_AUTHORIZATION_USER, username);
    }

}

要注意的是:

上面的例子是对请求进行过滤,校验用户身份信息,将用户信息放入请求头"Authorization-User"中,传递给具体的微服务,微服务解析即可拿到用户信息。

注册自定义的Filter

@Bean
public AccessFilter accessFilter() {
    return new AccessFilter();
}

保证能被spring boot扫描到即可。