SpringClond微服务架构篇 三 、网关gateway篇
Spring Cloud Gateway 是 Spring Cloud 家族中的新一代微服务网关框架,它为构建 API 网关提供了强大的功能。Spring Cloud Gateway 的核心组件之一就是过滤器,本文将详细介绍和三种过滤器的实现方式,并探讨如何在实践中高效地使用它们。文章汇总:springclond gateway 网关是通用微服务。本文档适用于使用效率的文章,在底层及文化概念层面为
·
网管概述:
Spring Cloud Gateway 是 Spring Cloud 家族中的新一代微服务网关框架,它为构建 API 网关提供了强大的功能。Spring Cloud Gateway 的核心组件之一就是过滤器,本文将详细介绍 GlobalFilter
、GatewayFilter
和 AbstractGatewayFilterFactory
三种过滤器的实现方式,并探讨如何在实践中高效地使用它们。
文章汇总:
Spring Cloud Gateway网关是通用微服务。本文档适用于使用效率的文章,在底层及文化概念层面未深入研究。
maven引入
<dependencies>
<!-- swagger聚合-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-gateway-spring-boot-starter</artifactId>
<version>4.4.0</version>
</dependency>
<!-- 请求调用-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<exclusions>
<exclusion>
<groupId>com.netflix.archaius</groupId>
<artifactId>archaius-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.pinyi.supply</groupId>
<artifactId>system-api</artifactId>
</dependency>
<!--nacos-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2021.0.4.0</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</dependency>
<!--gateway依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!--fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
全局拦截器
介绍:本拦截器逻辑不多。其中两个方法
permissionService.ignoreAuthentication(requestPath); // 验证是否白名单
permissionService.invalidAccessToken(token);//验证是否token有效
其中包含了传递用户信息头操作
经过这两层即可放行
/**
* 全局过滤器
*/
@Slf4j
@Order(Ordered.HIGHEST_PRECEDENCE)
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {
@Autowired
WhiteConfig whiteConfig;
@Resource
PermissionService permissionService;
// Getter or any other methods you need
public List<String> whiteList() {
return whiteConfig.getList();
}
/**
* 是否包含url
*
* @param url 地址
* @return 布尔值
*/
private boolean contains(String url) {
for (String s : Constants.AUTH_EXCLUDE_URLS) {
if (url.contains(s)) {
return true;
}
}
return false;
}
/**
* 响应信息
*/
private Mono<Void> writer(HttpStatus code, ServerHttpResponse response, String msg) {
response.setStatusCode(code);
response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
return response
.writeWith(Flux.just(response
.bufferFactory()
.wrap(JSON.toJSONBytes(HttpResult.error(code, msg)))));
}
//@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
// 请求路径
String requestPath = String.valueOf(exchange.getRequest().getPath());
log.info("网关路由路径:{}", requestPath);
// 打印访问情况
log.info("访问情况:{} {} {} {}", request.getRemoteAddress(), request.getMethod(), response.getStatusCode(), request.getPath());
MultiValueMap<String, String> requestQueryParams = request.getQueryParams();
log.info("请求参数:{}", requestQueryParams);
HttpResult result;
try {
result = permissionService.ignoreAuthentication(requestPath);
// 判断是否是白名单
if (result.getData().equals(true)) {
// 创建新的请求对象,并添加放行标识
ServerHttpRequest mutatedRequest = exchange.getRequest()
.mutate()
.header("Release-Flag", String.valueOf(result.getData())) // 添加自定义头部放行标识
.build();
// 使用新的请求对象创建新的 ServerWebExchange
ServerWebExchange mutatedExchange = exchange.mutate()
.request(mutatedRequest)
.build();
return chain.filter(mutatedExchange);
}
//验证是否存在权限
String token = request.getHeaders().getFirst("Authorization");
if (StringUtils.isBlank(token)) {
return writer(HttpStatus.UNAUTHORIZED, response, "暂未登录,请先登录");
}
//验证token
HttpResult invalided = permissionService.invalidAccessToken(token);
JSONObject data = JSON.parseObject(JSON.toJSONString(invalided.getData()), JSONObject.class);
if (invalided.getCode() != HttpStatus.OK.value()) {
return writer(HttpStatus.UNAUTHORIZED, response, invalided.getMsg());
} else {
if (!data.getBoolean("tokenStatus").equals(true)) {
return writer(HttpStatus.UNAUTHORIZED, response, invalided.getMsg());
}
}
// 创建新的请求对象,并添加放行标识
ServerHttpRequest mutatedRequest = exchange.getRequest()
.mutate()
.header("Release-Flag", String.valueOf(result.getData()))
.header("Login-user", data.getString("userName")) // 添加自定义头部放行标识
.build();
// 使用新的请求对象创建新的 ServerWebExchange
ServerWebExchange mutatedExchange = exchange.mutate()
.request(mutatedRequest)
.build();
return chain.filter(mutatedExchange);
} catch (Exception e) {
return writer(HttpStatus.UNAUTHORIZED, response, e.getMessage());
}
}
@Override
public int getOrder() {
return -2;
}
}
接口实现service
/**
* 统一鉴权service
* @author zhangzhiwei
*/
public interface PermissionService {
//
// /**
// * 调用签权服务,判断用户是否有权限
// *
// * @param authentication 权限标识
// * @param url 请求url
// * @param method 请求方法
// * @return true/false
// */
// boolean hasPermission(String authentication, String url, String method);
/**
* 获取正确的token
*
* @param authentication 权限标识
*/
HttpResult invalidAccessToken(String authentication) throws AuthenticationException;
/**
* 判断url是否不需要授权
* @param url 请求url
* @return true为不需要授权
*/
HttpResult ignoreAuthentication(String url) throws AuthenticationException;
}
impl层
/**
* 判断token是否有效
*
* @param authentication 权限标识
* @return ture 有效 false 无效
*/
@Override
public HttpResult invalidAccessToken(String authentication) throws AuthenticationException {
HttpResult httpResult = authService.invalidAccessToken(authentication);
return httpResult;
}
/**
* 判读那是否是白名单
*
* @param url 请求url
* @return true是 false不是
*/
@Override
public HttpResult ignoreAuthentication(String url) throws AuthenticationException {
return authService.isWhiteOpen(url);
}
使用feign进行远程调用
/**
* 鉴权接口
*
* @author zhangzhiwei
*/
@FeignClient(contextId = "authService", value = "security", fallbackFactory = RemoteAuthServiceFactory.class)
public interface RemoteAuthService {
/**
* 判断是否是白名单
*
* @param url 请求url
* @return true/false
*/
@GetMapping("/permission/isWhiteOpen")
public HttpResult isWhiteOpen(@RequestParam(value = "url") String url);
/**
* 验证token是否有效
*
* @param authentication token
* @return true/false
*/
@GetMapping("/permission/isValid")
public HttpResult invalidAccessToken(@RequestParam(value = "authentication") String authentication);
}
更多推荐
已为社区贡献2条内容
所有评论(0)