首页 > 其他分享 >责任链实现网关统一校验

责任链实现网关统一校验

时间:2023-01-02 22:32:55浏览次数:68  
标签:网关 capacity securityContext open 校验 责任 org import com

一、Commons Chain 介绍

Chain Of Responsibility(COR)模式也叫职责链模式或者职责连锁模式,是由GoF提出的23种软件设计模式的一种。Chain of Responsibility模式是行为模式之一,该模式构造一系列分别担当不同的职责的类的对象来共同完成一个任务,这些类的对象之间像链条一样紧密相连,所以被称作职责链模式。

Apache Commons Chain 提供了对COR模式的基础支持,简化和促进了实际应用CoR模式。CommonsChain实现了Chain of Responsebility和Command模式,其中的springboot配置方式使得调用方和Command的实现方的耦合度大大的降低,提高了灵活性。

二、Apache Commons Chain 核心组件

 

责任链实现网关统一校验_List

1、 Context接口

Context表示命令执行的上下文,在命令间实现共享信息的传递。 extends Map,父接口是Map,它只是一个标记接口。ContextBase实现了Context。对于web环境,可以使用WebContext类及其子类(FacesWebContext、PortletWebContext和ServletWebContext)。

2、Command接口

Commons Chain中最重要的接口,表示在Chain中的具体某一步要执行的命令。它只有一个方法:boolean execute(Context context)。如果返回true,那么表示Chain的处理结束,Chain中的其他命令不会被调用;返回false,则Chain会继续调用下一个Command,直到:

Command返回true;
Command抛出异常;
Chain的末尾;


3、Chain接口

它表示“命令链”,chain of command,要在其中执行的命令,需要先添加到Chain中,父接口是Command , ChainBase实现了它。

4、Filter接口

extends Command,它是一种特殊的Command。除了Command的execute方法之外,还包括了一个方法:boolean postProcess(Context context, Exception exception)。Commons Chain会在执行了Filter的execute方法之后,执行postprocess(不论Chain以何种方式结束)。Filter的执行execute的顺序与Filter出现在Chain中出现的位置一致,但是执行postprocess顺序与之相反。如:如果连续定义了filter1和filter2,那么execute的执行顺序是:filter1 -> filter2;而postprocess的执行顺序是:filter2 -> filter1。


三、Commons Chain 基本使用

   现在,我们模拟网关自定义校验方式看一下chain是工作实现。分为:​​校验actutor端点​​、​​黑名单校验​​、​​应用限流校验​​。3个工作类如下:

1.com.open.capacity.gateway.chain.ActuatorCommand

package com.open.capacity.gateway.chain;

import java.net.URI;
import java.util.List;

import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import com.google.common.collect.Lists;
import com.open.capacity.common.dto.ResponseEntity;
import com.open.capacity.common.properties.SecurityProperties;
import com.open.capacity.gateway.context.SecurityContext;

import cn.hutool.http.HttpStatus;

/**
*
* 端点命令 禁止通过网关访问服务的端点
*/
@Component
public class ActuatorCommand implements Command {

@Autowired
private SecurityProperties securityProperties;

private static final List<String> list = Lists.newArrayList();

static {
list.add("/actuator/**");
list.add("/*/actuator/**");
}

@Override
public boolean execute(Context context) throws Exception {

if (!securityProperties.getActuator().getEnable()) {
SecurityContext securityContext = (SecurityContext) context;
ServerHttpRequest request = securityContext.getExchange().getRequest();
URI uri = request.getURI();
String path = uri.getPath();
AntPathMatcher antPathMatcher = new AntPathMatcher();
boolean matchActuator = list.stream().anyMatch(item -> antPathMatcher.match(item, path));
if (matchActuator) {
securityContext.setCode(HttpStatus.HTTP_UNAUTHORIZED);
securityContext.setEntity(ResponseEntity.failed("禁止通过网关访问服务端点!"));
securityContext.setResult(true);
return true;
}
}

return false;
}

}

2.com.open.capacity.gateway.chain.BlackListCommand

package com.open.capacity.gateway.chain;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.URI;
import java.util.List;

import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import com.open.capacity.common.dto.ResponseEntity;
import com.open.capacity.common.properties.BlackListProperties;
import com.open.capacity.common.utils.IpAddressMatcher;
import com.open.capacity.gateway.context.SecurityContext;

import cn.hutool.http.HttpStatus;

/**
*
* 黑名单命令 禁止黑名单用户范围
*/
@Component
public class BlackListCommand implements Command {

@Autowired
private BlackListProperties blackListProperties;

@Override
public boolean execute(Context context) throws Exception {

if (blackListProperties.getEnable()) {
SecurityContext securityContext = (SecurityContext) context;
ServerHttpRequest request = securityContext.getExchange().getRequest();
URI uri = request.getURI();
String path = uri.getPath();
InetSocketAddress remoteAddress = request.getRemoteAddress();
if (remoteAddress == null) {
securityContext.setCode(HttpStatus.HTTP_UNAUTHORIZED);
securityContext.setEntity(ResponseEntity.failed("当前IP已被禁用!"));
securityContext.setResult(true);
return true;
}
InetAddress address = remoteAddress.getAddress();
String hostAddress = address.getHostAddress();
List<String> ipList = blackListProperties.getIpList();
for (String ip : ipList) {
IpAddressMatcher ipAddressMatcher = new IpAddressMatcher(ip);
boolean matches = ipAddressMatcher.matches(hostAddress);
if (matches) {
securityContext.setCode(HttpStatus.HTTP_UNAUTHORIZED);
securityContext.setEntity(ResponseEntity.failed("当前IP已被禁用!"));
securityContext.setResult(true);
return true;
}
}
AntPathMatcher antPathMatcher = new AntPathMatcher();
List<BlackListProperties.BlackList> services = blackListProperties.getServices();
for (BlackListProperties.BlackList service : services) {
String name = service.getName();
List<String> pathList = service.getPathList();
for (String p : pathList) {
String pattern = name.startsWith("/") ? name : "/" + name;
pattern = p.startsWith("/") ? pattern + p : pattern + "/" + p;
boolean match = antPathMatcher.match(pattern, path);
if (match) {
securityContext.setCode(HttpStatus.HTTP_UNAUTHORIZED);
securityContext.setEntity(ResponseEntity.failed("当前IP访问的目标地址已被禁用!"));
securityContext.setResult(true);
return true;
}
}
}
}

return false;
}

}

3.com.open.capacity.gateway.chain.RateLimitCommand

package com.open.capacity.gateway.chain;

import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;

import com.open.capacity.common.dto.ResponseEntity;
import com.open.capacity.common.properties.SecurityProperties;
import com.open.capacity.gateway.context.SecurityContext;
import com.open.capacity.gateway.service.IRateLimitService;
import com.open.capacity.gateway.utils.TokenUtil;

/**
* 限流命令
*/
@Component
public class RateLimitCommand implements Command {

@Autowired
private IRateLimitService rateLimitService;

@Autowired
private SecurityProperties securityProperties;

@Override
public boolean execute(Context context) throws Exception {

if (securityProperties.getRatelimit().getEnable()) {
SecurityContext securityContext = (SecurityContext) context;
ServerHttpRequest request = securityContext.getExchange().getRequest();
String accessToken = TokenUtil.extractToken(request);
String reqUrl = request.getPath().value();
// 超额自增处理
boolean flag = rateLimitService.checkRateLimit(reqUrl, accessToken);
// 超额限流
if (flag) {
securityContext.setCode(HttpStatus.TOO_MANY_REQUESTS.value());
securityContext.setEntity(ResponseEntity.failed("TOO MANY REQUESTS!"));
securityContext.setResult(true);
return true;
}
}

return false;
}

}


4.com.open.capacity.gateway.chain.SecurityFilterChain

 

package com.open.capacity.gateway.chain;

import javax.annotation.Resource;

import org.apache.commons.chain.impl.ChainBase;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

@Component
public class SecurityFilterChain extends ChainBase implements InitializingBean {

@Resource
private ActuatorCommand actuatorCommand;
@Resource
private BlackListCommand blackListCommand;
@Resource
private RateLimitCommand rateLimitCommand;

@Override
public void afterPropertiesSet() throws Exception {
// 将请求处理者角色加入链中
addCommand(actuatorCommand);
addCommand(blackListCommand);
addCommand(rateLimitCommand);

}

}


5.com.open.capacity.gateway.filter.SecurityChainFilter

package com.open.capacity.gateway.filter;

import javax.annotation.Resource;

import org.springframework.core.Ordered;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;

import com.open.capacity.common.utils.WebfluxResponseUtil;
import com.open.capacity.gateway.chain.SecurityFilterChain;
import com.open.capacity.gateway.context.SecurityContext;

import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Mono;

@Slf4j
@Component
public class SecurityChainFilter implements WebFilter, Ordered {

@Resource
private SecurityFilterChain securityFilterChain;

/**
* 最低优先级(最大值):0 大于 0 无效
*/
public static final int ORDERED = Ordered.HIGHEST_PRECEDENCE + 10000;

@Setter
private int order = ORDERED;

@Override
public int getOrder() {
return order;
}

@NonNull
@Override
public Mono<Void> filter(ServerWebExchange exchange, @NonNull WebFilterChain chain) {

// 封装请求对象
SecurityContext securityContext = new SecurityContext();
securityContext.setExchange(exchange);
try {
securityFilterChain.execute(securityContext);
} catch (Exception e) {
if (log.isTraceEnabled()) {
log.trace(" security chains exception :{}", e.getMessage());
}
}
// 获取处理结果
if (securityContext.isResult()) {
return WebfluxResponseUtil.responseWrite(exchange, securityContext.getCode(), securityContext.getEntity());
} else {
return chain.filter(exchange);
}

}

}

总结: Commons Chain实现了Chain of Responsebility和Command模式,Springboot配置方式使得调用方和Command的实现方的耦合度大大的降低,提高了灵活性。 


项目地址:

​https://github.com/owenwangwen/open-capacity-platform​

标签:网关,capacity,securityContext,open,校验,责任,org,import,com
From: https://blog.51cto.com/u_13005375/5984258

相关文章

  • 请求的参数的获取与校验(基本流程)
    请求的参数的获取与校验(基本流程)models/params.gopackagemodels//定义请求的参数typeParamSignUpstruct{ Usernamestring`json:"username"` Password......
  • linux中网关设置网络连接的影响
     001、[root@PC1network-scripts]#catifcfg-ens32TYPE="Ethernet"PROXY_METHOD="none"BROWSER_ONLY="no"BOOTPROTO="static"DEFROUTE="yes"IPV4_FAILURE_FAT......
  • Django之csrf校验 CBV加装饰器以及auth认证模块
    目录Django之csrf校验CBV加装饰器以及auth认证模块一、csrf跨站请求伪造二、csrf校验策略(在提交数据的位置添加唯一标识)三、CBV加装饰器四、auth认证模块五、auth认证......
  • 12、网关SpringCloud-Gateway
    网关作为流量的入口,常用功能包括路由转发、权限校验、限流控制等。而springcloudgateway作为SpringCloud官方推出的第二代网关框架,取代了Zuul网关。网关提供API......
  • 更加灵活、稳定,华为云虚拟专用网络VP双活网关优势明显!
    近年来,各企业为了方便内部信息传递、资源共享和业务交流都纷纷建立了更为便捷、安全、高效的内部网络,但随着业务的不断扩大,企业专线用网成本逐年提升。在此情况下,为节省运营......
  • element ui Form 自定义校验规则,验证手机号
    网站快速成型工具Element,一套为开发者、设计师和产品经理准备的基于Vue2.0的桌面端组件库指南了解设计指南,帮助产品设计人员搭建逻辑清晰、结构合理且高效易用的产品。​......
  • springcloud 学习八、Zuul 路由网关、路由的基本配置、路由访问映射规则
    前言案例的都是循序渐进的。案例的顺序:微服务讲诉->父工程maven的module建立和rest风格的请求->eureka的学习、三大组件,服务注册与消费->eureka的集群操作->ribbon的负载均......
  • 基于AI边缘智能网关的工业质检应用
    成品质量检验是工业生产最后必不可少的环节,随着我国工业化的蓬勃发展,工业产品日益迈向高端化、精密化,对于工业产品的质量检验要求和投入成本也在不断提高,产品质检涉及到比......
  • 高性能网关基石——OpenResty
    什么是OpenRestyOpenResty一个基于Nginx的高性能Web平台,能够方便地搭建处理超高并发的动态Web应用、Web服务和动态网关。例如有名的Kong网关和国产新秀ApiSIX......
  • 基于边缘智能网关的智能售货机应用
    自动售货机是生活中很常见的商业基础设施,已经广泛部署在商圈、公园、写字楼等场景,为公众提供便利的零售服务。近年来随着物联网技术的发展,自动售货机的智能化水平也需要不......