1.Spring Cloud Gateway简介

  Spring Cloud Gateway是Spring Cloud官方推出的第二代网关框架,取代Zuul网关。网关作为流量的,在微服务系统中有着非常作用,网关常见的功能有路由转发、权限校验、限流控制等作用。

  2.创建工程

  本文我们采用最新的Spring Cloud 版本“Finchley.SR2”,注意该版本对应Spring Boot为2x。官方推荐的是:2.0.6.RELEASE版本。

  父项目导入如下包:

  org.springframework.boot

  spring-boot-starter-parent

  2.0.8.RELEASE

  pom

  import

  org.springframework.cloud

  spring-cloud-dependencies

  Finchley.SR2

  pom

  import

  org.mybatis.spring.boot

  mybatis-spring-boot-starter

  1.3.0

  com.alibaba

  dubbo

  2.6.6

  com.alibaba.spring

  spring-context-support

  1.0.2

  org.apache.curator

  curator-framework

  4.0.1

  org.apache.zookeeper

  zookeeper

  3.4.6

  org.hibernate

  hibernate-validator

  6.0.9.Final

  gateway网关服务导入如下jar:

  org.springframework.cloud

  spring-cloud-starter-gateway

  org.springframework.boot

  spring-boot-starter-test

  test

  org.springframework.boot

  spring-boot-starter-aop

  com.alibaba

  dubbo

  com.alibaba.spring

  spring-context-support

  org.apache.curator

  curator-framework

  org.apache.zookeeper

  zookeeper

  org.slf4j

  slf4j-log4j12

  log4j

  log4j

  com.uaf.credit

  uaf-credit-api

  org.springframework.boot

  spring-boot-starter-web

  父项目统一管理jar包的版本,子项目就不必再添加jar对应的版本号

  网关服务的yml配置如下:

  server:

  port: 8817

  spring:

  application:

  name: uaf-credit-gateway

  security:

  user:

  name: wxt

  password: wxt2016

  cloud:

  gateway:

  routes:

  - id: credit-auth-route

  uri: http://10.168.xx.xx:8820/credit-auth/v1

  predicates:

  - Path=/credit-auth/v1/* #路径匹配,匹配所有请求路径以/credit-auth开头的用户请求

  logging:

  config: classpath:logback.xml

  3.Spring Cloud Gateway过滤器

  Spring-Cloud-Gateway的filter包中吉接口有如下三个,GatewayFilter,GlobalFilter,GatewayFilterChain,GlobalGilter 全局过滤器接口与 GatewayFilter 网关过滤器接口具有相同的方法定义。全局过滤器是一系列特殊的过滤器,会根据条件应用到所有路由中。网关过滤器是更细粒度的过滤器,作用于指定的路由中。

  我们可以配置多个GlobalFilter过滤器,通过指定getOrder()方法的优先级来配置过滤器的执行顺序。

  @Component

  public class RequestAuthFilter implements GlobalFilter, Ordered {

  /**

  * 请求方式验证过滤器

  * @param exchange

  * @param chain

  * @return reactor.core.publisher.Mono

  * 作者:will

  * 日期:2019/4/4 14:46

  */

  @Override

  public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {

  ServerHttpRequest serverHttpRequest = exchange.getRequest();

  String method = serverHttpRequest.getMethodValue();

  if(!"POST".equals(method)){

  ServerHttpResponse response = exchange.getResponse();

  String message= new ResponseUtils().CreditRespMsg(CreditException.ERR_100008,"非法请求",null);

  byte[] bits = message.getBytes(StandardCharsets.UTF_8);

  DataBuffer buffer = response.bufferFactory().wrap(bits);

  response.setStatusCode(HttpStatus.UNAUTHORIZED);

  //指定编码,否则在浏览器中会中文乱码

  response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");

  return response.writeWith(Mono.just(buffer));

  }

  return chain.filter(exchange);

  }

  /**

  * 优先级

  * @return int 数字越大优先级越低

  * 作者:will

  * 日期:2019/4/4 13:36

  */

  @Override

  public int getOrder() {

  return 0;

  }

  }

  4.Spring boot Security认证

  Spring Security致力于为Java应用提供认证和授权管理。它是一个强大的,高度自定义的认证和访问控制框架,这句话包括两个关键词:Authentication(认证)和 Authorization(授权,也叫访问控制)。

  需要安全认证的服务需要导入如下Jar:

  org.springframework.boot

  spring-boot-starter-security

  yml配置:

  server:

  port: 8820

  servlet:

  context-path: /credit-auth

  spring:

  application:

  name: uaf-credit-auth

  security:

  user:

  name: wxt

  password: wxt2016

  roles:

  - USER

  logging:

  config: classpath:logback.xml

  接下来配置认证类:

  @Configuration

  @EnableWebSecurity

  public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  @Override

  protected void configure(HttpSecurity http) throws Exception {

  /**表示所有的访问都必须进行认证处理后才可以正常进行*/

  http.httpBasic().and().authorizeRequests().anyRequest().fullyAuthenticated();

  /**所有的Rest服务一定要设置为无状态,以提升操作性能*/

  http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

  /**关闭csrf避免POST请求时出现401异常*/

  http.csrf().disable();

  http.authorizeRequests().antMatchers(org.springframework.http.HttpMethod.GET).permitAll();

  }

  }

  这里有个问题,外面的服务若请求我们的服务需要进行Security认证,但我们的网关应该需要免认证。

  我们通过Gateway的GlobalFilter过滤器的方式实现:

  @Component

  public class OAuthSignatureFilter implements GlobalFilter, Ordered {

  /**授权访问用户名*/

  @Value("${spring.security.user.name}")

  private String securityUserName;

  /**授权访问密码*/

  @Value("${spring.security.user.password}")

  private String securityUserPassword;

  /**

  * OAuth过滤器

  * @param exchange

  * @param chain

  * @return reactor.core.publisher.Mono

  * 作者:will

  * 日期:2019/4/4 13:36

  */

  @Override

  public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {

  /**oauth授权*/

  String auth= securityUserName.concat(":").concat(securityUserPassword);

  String encodedAuth = new sun.misc.BASE64Encoder().encode(auth.getBytes(Charset.forName("US-ASCII")));

  //注意Basic后面有空格

  String authHeader= "Basic " +encodedAuth;

  //向headers中放授权信息

  ServerHttpRequest serverHttpRequest = exchange.getRequest().mutate().header("Authorization",authHeader).build();

  //将现在的request变成change对象

  ServerWebExchange build =exchange.mutate().request(serverHttpRequest).build();

  return chain.filter(build);

  }

  /**

  * 优先级

  * @return int 数字越大优先级越低

  * 作者:will

  * 日期:2019/4/4 13:36

  */

  @Override

  public int getOrder() {

  return 2;

  }

  5.新增自定义过滤器

  gateway里面可以自定义普通filter,也可以创建自定义的GlobalFilter,我们通过继承AbstractGatewayFilterFactory实现自定义过滤器。

  yml新增如下配置:

  spring:

  application:

  name: uaf-credit-gateway

  security:

  user:

  name: wxt

  password: wxt2016

  cloud:

  gateway:

  routes:

  - id: credit-auth-route

  uri: http://10.168.xx.xx:8820/credit-auth/v1

  predicates:

  - Path=/credit-auth/v1/* #路径匹配,匹配所有请求路径以/credit-auth开头的用户请求

  filters:无锡人流医院 http://xmobile.wxbhnk120.com/

  - CreditFilter #注意与定义的过滤器类名一致

  新增CreditFilter.java类,自定义过滤器的优先级低于GlobalFilter

  @Configuration

  public class CreditFilter extends AbstractGatewayFilterFactory {

  public CreditFilter() {

  super(Config.class);

  }

  @Override

  public GatewayFilter apply(Config config) {

  MySlf4j.textInfo("进入自定义Credit过滤器");

  return (exchange, chain) -> {

  String jwtToken = exchange.getRequest().getHeaders().getFirst("Authorization");

  //校验jwtToken的合法性

  if (jwtToken != null) {

  // 合法

  // 将用户id作为参数传递下去

  return chain.filter(exchange);

  }

  //不合法(响应未登录的异常)

  ServerHttpResponse response = exchange.getResponse();

  //设置headers

  HttpHeaders httpHeaders = response.getHeaders();

  httpHeaders.add("Content-Type", "application/json; charset=UTF-8");

  httpHeaders.add("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");

  //设置body

  String warningStr = "未登录或登录超时";

  DataBuffer bodyDataBuffer = response.bufferFactory().wrap(warningStr.getBytes());

  return response.writeWith(Mono.just(bodyDataBuffer));

  };

  }

  public static class Config {

  }

  @Bean

  public CreditFilter creditFileterFactory() {

  return new CreditFilter();

  }

  }

  至此我们的Gateway及相关的授权认证配置完成。