目录
一、启动springcloud基础服务以及业务服务
例如:访问业务微服务XiZhiActApp的接口
通过具体微服务的端口号访问
例如这里的端口号为8004:http://localhost:8004/business/get/1
二、通过网关访问具体微服务的接口
例如访问网关的端口号为9572:http://localhost:9527/act/business/get/1
三、网关的配置
server:
port: 9527
spring:
application:
name: xizhi-gateway
devtools:
restart:
enabled: true
profiles:
active: dev
cloud:
config:
fail-fast: true
name: ${spring.application.name}
profile: ${spring.profiles.active}
discovery:
enabled: true
service-id: xizhi-config
gateway:
discovery:
locator:
enabled: true
routes:
# 认证中心
- id: xizhi-auth
uri: lb://xizhi-auth
predicates:
- Path=/auth/**
filters:
# 验证码处理
- CacheRequest
# - ImgCodeFilter
- StripPrefix=1
# 限流配置
- name: RequestRateLimiter
args:
key-resolver: '#{@remoteAddrKeyResolver}'
#允许用户每秒处理多少个请求
redis-rate-limiter.replenishRate: 2
#令牌桶的容量,允许在一秒钟内完成的最大请求
redis-rate-limiter.burstCapacity: 20
# 降级配置
- name: Hystrix
args:
name: fallbackcmd
fallbackUri: 'forward:/fallback'
# act
- id: xizhi-activiti
uri: lb://xizhi-activiti
predicates:
- Path=/act/**
filters:
- StripPrefix=1
filters:
# 限流配置
- StripPrefix=1
- name: RequestRateLimiter
args:
key-resolver: '#{@remoteAddrKeyResolver}'
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
# 降级配置
- name: Hystrix
args:
name: fallbackcmd
fallbackUri: 'forward:/fallback'
eureka:
client: #客户端注册进eureka服务列表内
service-url:
defaultZone: http://localhost:7001/eureka
#defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: ${spring.application.name}:${server.port}
prefer-ip-address: true #访问路径可以显示IP地址
hystrix:
command:
default: #default全局有效,service id指定应用有效
execution:
timeout:
enabled: true
isolation:
thread:
timeoutInMilliseconds: 5000 #断路器超时时间,默认1000ms
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: '*'
例如act服务的网关配置:
可以看到路径为 /act,所以上面通过网关访问的接口为http://localhost:9527/act/business/get/1
# act
- id: xizhi-activiti
uri: lb://xizhi-activiti
predicates:
- Path=/act/**
filters:
- StripPrefix=1
四、网关的鉴权拦截功能演示
例如提示访问接口token不能为空
什么是token?
token的意思是“令牌”,是服务端生成的一串字符串,作为客户端进行请求的一个标识。
当用户第一次登录后,服务器生成一个token并将此token返回给客户端,以后客户端只需带上这个token前来请求数据即可,无需再次带上用户名和密码。
简单token的组成;uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,token的前几位以哈希算法压缩成的一定长度的十六进制字符串。为防止token泄露)。
例如访问京东网站,开发者模式找到一个接口,一般截图箭头那里就是token
代码实现网关鉴权
/**
* 网关鉴权
*/
@Slf4j
@Component
public class AuthFilter implements GlobalFilter, Ordered
{
// 排除过滤的 uri 地址
// swagger排除自行添加
private static final String[] whiteList = {"/auth/login", "/user/register", "/system/v2/api-docs",
"/auth/captcha/check", "/auth/captcha/get","/auth/login/slide"};
@Resource(name = "stringRedisTemplate")
private ValueOperations<String, String> ops;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
{
String url = exchange.getRequest().getURI().getPath();
log.info("url:{}", url);
// 跳过不需要验证的路径
if (Arrays.asList(whiteList).contains(url))
{
return chain.filter(exchange);
}
String token = exchange.getRequest().getHeaders().getFirst(Constants.TOKEN);
// token为空
if (StringUtils.isBlank(token))
{
return setUnauthorizedResponse(exchange, "token can't null or empty string");
}
String userStr = ops.get(Constants.ACCESS_TOKEN + token);
if (StringUtils.isBlank(userStr))
{
return setUnauthorizedResponse(exchange, "token verify error");
}
JSONObject jo = JSONObject.parseObject(userStr);
String userId = jo.getString("userId");
// 查询token信息
if (StringUtils.isBlank(userId))
{
return setUnauthorizedResponse(exchange, "token verify error");
}
// 设置userId到request里,后续根据userId,获取用户信息
ServerHttpRequest mutableReq = exchange.getRequest().mutate().header(Constants.CURRENT_ID, userId)
.header(Constants.CURRENT_USERNAME, jo.getString("loginName")).build();
ServerWebExchange mutableExchange = exchange.mutate().request(mutableReq).build();
return chain.filter(mutableExchange);
}
private Mono<Void> setUnauthorizedResponse(ServerWebExchange exchange, String msg)
{
ServerHttpResponse originalResponse = exchange.getResponse();
originalResponse.setStatusCode(HttpStatus.UNAUTHORIZED);
originalResponse.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
byte[] response = null;
try
{
response = JSON.toJSONString(R.error(401, msg)).getBytes(Constants.UTF8);
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
DataBuffer buffer = originalResponse.bufferFactory().wrap(response);
return originalResponse.writeWith(Flux.just(buffer));
}
@Override
public int getOrder()
{
return -200;
}
}
鉴权之后访问的效果如图
五、网关的作用
如上通过自己的实践演示,可以得出网关的作用有
1、作为整个项目的统一入口,所有的请求首先都通过网关再请求转发到具体服务,好处有可以统一管理请求。
2、鉴权,安全保障,不是所有的请求都可以访问我们的系统,所以可以拦截黑名单、或者恶意请求、网络限流(一瞬间的大量请求容易导致系统崩溃,例如我们的学校的选课系统经常会崩溃)。