前言
SpringCloud Gateway建立在Spring Framework5、Project Reactor和Spring Boot2.0之上,使用WebFlux非阻塞API
什么是WebFlux?
官网:https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html
传统的Web框架,比如:struts2,springmvc等都是基于Servlet API与Servlet容器基础之上运行的。
但是
在Servlet3.1之后有了异步非阻塞的支持。而WebFlux是一个典型非阻塞异步的框架,它的核心是基于Reactor的相关API实现的。相对于传统的web框架来说,它可以运行在诸如Netty,Undertow及支持Servlet3.1的容器上。非阻塞式+函数式编程。
Spring WebFlux是Spring5引入的新的响应式框架,区别于Spring MVC,它不需要依赖Servle API,它是完全异步非阻塞的,并且基于Reactor来实现响应式流程规范
SpringCloudGateway的过滤器
通过全局过滤器GlobalFilter实现对header或body信息的判断、鉴权、拦截。
通过Request Header鉴权
@Slf4j
@Component
public class HeaderFilter implements GlobalFilter {private static final String defUsername = "admin" ;private static final String defPassword = "12345" ;//过滤器的优先级,数值越⼩,优先级越⾼@Order(0)@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 方式1:通过http header获取参数ServerHttpRequest request = exchange.getRequest();String username = request.getHeaders().getFirst("username");String password = request.getHeaders().getFirst("password");String contentType = request.getHeaders().getFirst("content-type");log.info("Request Header:[username:" + username + ",password:" + password + ",contentType:" + contentType + "]");if (!defUsername.equals(username) || ! defPassword.equals(password)) {//认证失败,返回401System.out.println("当前用户未登陆,返回:" + HttpStatus.UNAUTHORIZED);exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);return exchange.getResponse().setComplete();}//表⽰继续向下执⾏return chain.filter(exchange);}}
通过Request Body鉴权
/*** ReadJsonBody* 解析body判断json中的用户名、密码是否正确* @param exchange* @param chain* @return
*/
@Slf4j
@Component
public class BodyFilter implements GlobalFilter {private static final String defUsername = "admin" ;private static final String defPassword = "12345" ;private static final List<HttpMessageReader<?>> messageReaders = HandlerStrategies.withDefaults().messageReaders();/*** ReadJsonBody** @param exchange* @param chain* @return*/@Order(0)@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {return DataBufferUtils.join(exchange.getRequest().getBody()).flatMap(dataBuffer -> {byte[] bytes = new byte[dataBuffer.readableByteCount()];dataBuffer.read(bytes);DataBufferUtils.release(dataBuffer);Flux<DataBuffer> cachedFlux = Flux.defer(() -> {DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);DataBufferUtils.retain(buffer);return Mono.just(buffer);});ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) {@Overridepublic Flux<DataBuffer> getBody() {return cachedFlux;}};ServerWebExchange mutatedExchange = exchange.mutate().request(mutatedRequest).build();return ServerRequest.create(mutatedExchange, messageReaders).bodyToMono(String.class).flatMap(objectValue -> {String str = "[GatewayContext]Read JsonBody:" + objectValue ;Gson gson = new Gson();JsonObject obj = gson.fromJson(objectValue, JsonElement.class).getAsJsonObject();JsonElement obj_username = obj.get("username");JsonElement obj_password = obj.get("password");boolean isnull = obj_username == null || obj_password == null ;if (isnull || !defUsername.equals(obj_username.getAsString()) || !defPassword.equals(obj_password.getAsString())) {// 认证失败,返回401log.info("{} 用户名或密码错误,返回{}",str,HttpStatus.UNAUTHORIZED);mutatedExchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);return mutatedExchange.getResponse().setComplete();}else {log.info("{},正确",str);}return chain.filter(exchange.mutate().request(mutatedRequest).build());});});}
}