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及相关的授权认证配置完成。