服务网关的概念有点类似于传统的反向代理服务器(如nginx),但反向代理一般都只是做业务无关的转发请求,而服务网关与服务的整合程度更高,可以看作也是整个服务体系的组成部分,通过过滤器等组件可以在网关中集成一些业务处理的操作(比如权限认证等)。Spring Cloud Gateway正是Spring官方推出的服务网关的实现框架,它主要包含三个核心的概念:
Route: 负责将某个外部请求路由到一个合适的地址,包含一个ID,一个目标地址,一系列的Predicate和Filter;
Predicate: 基于Java 8 Function Predicate的断言机制,用于将请求匹配到某一个Route
Filter: 类似于Servlet filter,可以在请求传递给下一级处理器之前对请求或响应进行修改,用于实现权限验证,日志记录,限流等功能
我们现在来为我们的demo项目加入一个服务网关。首先需要创建一个新的模块,名字叫Gateway,在pom.xml中加入如下依赖:
org.springframework.cloud spring-cloud-starter-gateway在application.yml中加入如下内容:
server:
port: 9000
spring:
application:
name: gateway
cloud:
consul:
host: 192.168.1.220
port: 8500
discovery:
prefer-ip-address: true
gateway:
routes:
- id: order-service
#lb协议会激活LoadBalancerClient来解析后续的地址,自动根据注册的服务实例进行负载均衡
uri: lb://order-service
filters:
- Log
# 转发时去掉请求地址的服务名前缀
- StripPrefix=1
predicates:
- Path=/order-service
@Override
public int getOrder() {
return 1;
}
}
功能很简单,就是对请求头部的token进行校验,如果成功就将从token中解析出来的用户账户信息放入转发的请求头中供后端的业务服务使用,否则返回UNAUTHORIZED。这个Filter也需要注册到容器中:
@Bean
public AuthGlobalFilter authGlobalFilter(AuthService authService) {
return new AuthGlobalFilter(authConfig, authService);
}
对token进行校验的核心逻辑在authService.verifyToken方法中,代码如下:
public boolean verifyToken(String url, String token) {
if (Strings.isNullOrEmpty(token)) {
return false;
}
//获取每个Url所对应的权限控制符
String urlPermission = getUrlPermission(url);
if ("anno".equals(urlPermission)) {
return true;
} else {
//获取token中包含的用户唯一标识
String account = jwtHelper.getAccount(token);
if (Strings.isNullOrEmpty(account)) {
return false;
}
//获取token的加密密钥
String secret = getUserSecret(account);
//校验accessToken
if (jwtHelper.verify(token, secret) == null) {
return false;
}
// 如果url仅要求验证用户有效性,则直接通过
if (Strings.isNullOrEmpty(urlPermission) ||
"authc".equals(urlPermission)) {
return true;
}
// 进一步判断用户权限
if (urlPermission.startsWith("perms")) {
Set userPerms = this.getUserPermissions(account);
String perms = urlPermission.substring(urlPermission.indexOf("[") + 1, urlPermission.lastIndexOf("]"));
return userPerms.containsAll(Arrays.asList(perms.split(",")));
}
}
return false;
}
服务网关首先需要知道不同的服务地址需要什么样的权限才允许访问,这里采用了类似Shiro配置的格式,类似这样如下的格式,实际环境中可能是从数据库或配置文件中读取:
public Map getAllUrlPermissionsMap() {
Map urlPermissionsMap = Maps.newHashMap();
urlPermissionsMap.put("/api/order/orders", "authc");
urlPermissionsMap.put("/api/order/create-order", "perms[order]");
urlPermissionsMap.put("/api/storage/**", "perms[storage]");
return urlPermissionsMap;
}
通过Spring 提供的工具类AntPathMatcher,就可以查询到每个请求url所需要的权限标识符,再根据权限标识符去检查token对应的用户是否具备相应的权限
引用该文章,点击查看详情。



