Zuul:Pre和Post过滤器(下)

可以看到所有的请求都会经过他,那么我们现在要对这个请求做一个权限的校验,加入没有Zuul这个服务,

那你Server A/B/C,都要校验一次,这个每个服务都要做一次,所以权限校验我们可以放到Zuul统一的实现掉,

接下来我们演示如何对请求进行统一的校验,我们现在来做这么一件事,希望所有经过Zuul的请求,都要有一个

参数叫做Token,并且内容不能为空,如果你不带这个参数的话,如果不带这个参数的话,那么就权限校验不通过,

我们新建一个包叫filter,下面新建一个TokenFilter

import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;

import javax.servlet.http.HttpServletRequest;

import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;

@Component
public class TokenFilter extends ZuulFilter {
    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return PRE_DECORATION_FILTER_ORDER - 1;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        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;
    }
}

/**
 * {@code 401 Unauthorized}.
 * @see <a href="http://tools.ietf.org/html/rfc7235#section-3.1">HTTP/1.1: Authentication, section 3.1</a>
 */
UNAUTHORIZED(401, "Unauthorized"),

继承ZuulFilter

com.netflix.zuul.ZuulFilter

这里要实现几个方法,实现这四个方法,这里有一个常量类FilterConstants,这里我们要做的是参数校验,用这个PRE_TYPE

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

/**
 * {@link ZuulFilter#filterType()} pre type.
 */
String PRE_TYPE = "pre";

这个filterOrder这是顺序,这个顺序用什么顺序呢,正如我们之前所说,一种过滤器一个类型下面,有很多个过滤器,

这些都是pre的,这个ORDER我们填什么呢,我们把顺序放到这个过滤器之前,这些顺序越小的越靠前,越小的优先级越高,

放到他前面我们减1就好了

@Override
public int filterOrder() {
	return PRE_DECORATION_FILTER_ORDER - 1;
}

/**
 * Filter Order for {@link org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter}
 */
int PRE_DECORATION_FILTER_ORDER = 5;

这也是官方推荐的一个写法,

@Override
public boolean shouldFilter() {
	return true;
}

这里就是我们的逻辑

@Override
public Object run() {
	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;
}

我们从一个对象里面拿到一个请求的内容,叫做RequestContext,这也是Zuul他自己封装的,获取当前的一个上下文,

RequestContext requestContext = RequestContext.getCurrentContext();

在从这里面拿到Request,拿到Request之后大家就熟了,从这我们就可以拿到Token了,这里写点注释,这里我们是从参数里面去拿,

你也可以从Cookie或者header里面获取,基本上也就放到这里面了,获取到了之后判断一下,如果他是空的话呢,这个时候返回没有

权限,往requestContext这里面设置一些值就好了,首先设置sendZuulResponse为false,false是不通过,再设置一个HTTP的状态码,

状态码权限不足我们一般是用401,我们也可以直接写枚举HttpStatus.UNAUTHORIZED.value()

BAD_REQUEST(400, "Bad Request"),
/**
 * {@code 401 Unauthorized}.
 * @see <a href="http://tools.ietf.org/html/rfc7235#section-3.1">HTTP/1.1: Authentication, section 3.1</a>
 */
UNAUTHORIZED(401, "Unauthorized"),

org.springframework.http.HttpStatus.UNAUTHORIZED

http://localhost:8040/myProduct/product/list?token=1234

现在地址带了token,没问题和之前一样

http://localhost:8040/myProduct/product/list

如果不带TOKEN就401,返回的是401,权限没有通过,会走这个校验的逻辑,你的业务类型可能也不只是判断是否为空,

你拿到这个值之后也可以从数据库里面去读,从Redis里面去比较,都是可以的,我们也可以自定义一个POST Filter,

就是请求到了目标服务,返回了结果之后,对结果进行加工,我们从返回的头里面写一些东西吧

@Component
public class AddResponseHeaderFilter extends ZuulFilter{
    @Override
    public String filterType() {
        return POST_TYPE;
    }

    @Override
    public int filterOrder() {
        return SEND_RESPONSE_FILTER_ORDER - 1;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletResponse response = requestContext.getResponse();
        response.setHeader("X-Foo", UUID.randomUUID().toString());
        return null;
    }
}

同样的继承ZuulFilter,type是POST_TYPE

/**
 * {@link ZuulFilter#filterType()} post type.
 */
String POST_TYPE = "post";

org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.POST_TYPE

filterOrder这个也是比较有讲究的,我们再去看一下order,如果我们自定义POST order的话,

我们会把它放到这个之前,也就是放到这个fiter之前,所以我们选中这个再减1

@Override
public int filterOrder() {
	return SEND_RESPONSE_FILTER_ORDER - 1;
}

/**
 * Filter Order for {@link org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter#filterOrder()}
 */
int SEND_RESPONSE_FILTER_ORDER = 1000;

org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SEND_RESPONSE_FILTER_ORDER

优先级在他之前了,也是获取requestContext

@Override
public Object run() {
	RequestContext requestContext = RequestContext.getCurrentContext();
	HttpServletResponse response = requestContext.getResponse();
	response.setHeader("X-Foo", UUID.randomUUID().toString());
	return null;
}

不是request,而是要拿到结果了,我们从返回的结果里面写东西了,设置一个header,header名随便设置一个,

生成一下随机数,这就写完了

http://localhost:8040/myProduct/product/list?token=1234

结果是返回了,返回头里面有没有我们添加进去的信息呢,Response Header有吧

以上就是自定义POST Filter的内容
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.learn.cloud</groupId>
	<artifactId>api-gateway</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	 <parent>
	   <groupId>cn.learn</groupId>
	   <artifactId>microcloud02</artifactId>
	   <version>0.0.1</version>
	 </parent>
	
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>	
	
	<dependencies>
		<!-- <dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-config</artifactId>
		</dependency> -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-eureka</artifactId>
		</dependency>
        <!-- <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
        </dependency> -->
		<dependency>
		    <groupId>org.springframework.cloud</groupId>
		    <artifactId>spring-cloud-starter-zuul</artifactId>
		</dependency>
	</dependencies>
	
	<!-- 这个插件,可以将应用打包成一个可执行的jar包 -->
	<build>
	    <plugins>
	        <plugin>
	            <groupId>org.springframework.boot</groupId>
	            <artifactId>spring-boot-maven-plugin</artifactId>
	        </plugin>
	    </plugins>
	</build>

  
</project>
package com.learn.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@EnableZuulProxy
@SpringBootApplication
public class APIGatewayApplication {
  public static void main(String[] args) {
    SpringApplication.run(APIGatewayApplication.class, args);
  }

}
package com.learn.cloud.filter;

import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;

import javax.servlet.http.HttpServletRequest;

import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;

@Component
public class TokenFilter extends ZuulFilter {
    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return PRE_DECORATION_FILTER_ORDER - 1;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        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;
    }
}
package com.learn.cloud.filter;

import java.util.UUID;

import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Component;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;

import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.POST_TYPE;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SEND_RESPONSE_FILTER_ORDER;

@Component
public class AddResponseHeaderFilter extends ZuulFilter{
    @Override
    public String filterType() {
        return POST_TYPE;
    }

    @Override
    public int filterOrder() {
        return SEND_RESPONSE_FILTER_ORDER - 1;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletResponse response = requestContext.getResponse();
        response.setHeader("X-Foo", UUID.randomUUID().toString());
        return null;
    }
}
server.port=8040
spring.application.name=api-gateway
eureka.instance.prefer-ip-address=true
eureka.instance.instance-id=${spring.application.name}:${spring.cloud.client.ipAddress}:${spring.application.instance_id:${server.port}}
eureka.client.serviceUrl.defaultZone=http://admin:1234@10.40.8.152:8761/eureka
#eureka.instance.appname=api-gateway
#zuul.routes.user-route.service-id=product
#zuul.ignoredServices=microservice-consumer-movie-ribbon-hystrix
#zuul.routes.user-route.path=/user/**
#zuul.routes.user-route.url=http://localhost:7900/
#ribbon.eureka.enabled=false
#microservice-simple-provider-user.ribbon.listOfServers=http://localhost:7900/,http://localhost:7901/

zuul.routes.myProduct.path=/myProduct/**
zuul.routes.myProduct.service-id=product
zuul.routes.myProduct.sensitiveHeaders=
#zuul.routes.product=/myProduct/**
management.security.enabled=false

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值