最近在写自己的毕业设计,我本着能与众不同点就不同一点的想法,脑子一热决定,“要不用分布式来写个毕业设计吧”然后悲惨的生活开始了
问题出处
大家都知道http连接是无状态的,所以服务器压根不会知道你到底是谁,你来过吗?
所以咋办?用session咯!但是呢由于现在都流行前后端分离,这两玩意都不在同一个服务器上呀,那session就不能共享了呀。
所以就出现了一个好东西——token,它就像你每天上班都要带的工牌,你不带门口保安叔叔可不让你进去呀。
但是呢还有个问题,我这分布式好多个功能模块噢,那我不得每个模块都来个token检验,那多麻烦呀。好了废话那么多,本次主角该登场了。
什么是网关
网关是微服务最边缘的服务,直接暴露给用户,用来做用户和微服务的桥梁
网关能做啥呢
网关可以实现负载均衡,可 以实现 token 拦截,权限验证,限流等操作。
等等token拦截,权限验证,那不就可以对所有的请求进行token校验然后再路由转发给其他的功能模块了吗?所以
那必须动手做呀
Gateway
从这张图我们可以看出来gateway的核心就是一个一个的过滤器,所以token拦截自然也是在过滤器中完成的啦。这里再上一个图
token校验的实现
/**
* 使用网关进行token校验拦截
* 注意这里需要创建这个对象所以需要依赖注入创建
* */
@Component
public class TokenCheckFilter implements GlobalFilter, Ordered {
/**
* 制定好放行的路径
* */
public static final List<String> ALLOW_URL = Arrays.asList("/login-service/doLogin","/doLogin");
@Autowired
private RedisTemplate redisTemplate;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
/**
* 一般和前端约定好 一般把token放在请求头里面 一般key为Authorization (授权的意思) value 为bearer token
* 拿到请求url判断是否为登录url是就放行,不是继续操作
* 拿到请求头
* 拿到token
* 校验
* 放行/拦截
* */
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
if(ALLOW_URL.contains(path)){
return chain.filter(exchange);
}
//检查
HttpHeaders headers = request.getHeaders();
List<String> authorization = headers.get("Authorization");
if(!CollectionUtils.isEmpty(authorization)){
//如果authorization集合不为空
//获取第一个为token
String token = authorization.get(0);
//判断给token里面的值是不是空字符串
if(StringUtils.hasText(token)){
//不为空
//约定好的有前缀的bearer token
String realToken = token.replaceFirst("bearer ","");
//判断realToken是否为空以及redis数据库是否包含
if(StringUtils.hasText(realToken)&&redisTemplate.hasKey(realToken)){
return chain.filter(exchange);
}
}
}
//如果不符合就不给访问
ServerHttpResponse response = exchange.getResponse();
response.getHeaders().set("content-type","application/json;charset=utf-8");
HashMap<String,Object> map = new HashMap<>(4);
//返回401
map.put("code", HttpStatus.UNAUTHORIZED.value());
map.put("msg","未授权");
ObjectMapper objectMapper = new ObjectMapper();
byte [] bytes = new byte[0];
try {
bytes=objectMapper.writeValueAsBytes(map);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
DataBuffer wrap = response.bufferFactory().wrap(bytes);
return response.writeWith(Mono.just(wrap));
}
@Override
public int getOrder() {
//配置优先级 越小越先执行
return -1;
}
}