设计模式-过滤器模式(使用案例)

news2025/1/23 13:09:52

        过滤器模式(Filter Pattern)或标准模式(Criteria Pattern)是一种设计模式,这种模式允许开发人员使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来。这种类型的设计模式属于结构型模式,它结合多个标准来获得单一标准。

        业务场景:每次请求通过网关,需要验证请求头是否携带 token,sign签名等

        类图:

AuthService:所有滤器类都必须实现的接口

AuthTokenServiceImpl:Token验证过滤器

AuthSignServiceImpl:签名验证过滤器

AuthFactory:过滤器工厂,利用SpringBoot功能特性,实现自动获取过滤器

AuthDTO:过滤器所需要的参数

AuthGatewayFilterFactory:权限校验过滤器(gateway)

AuthService:

/**
 * @Author: wmh
 * @Description: 权限校验过滤器
 * @Date: 2023/8/3 18:19
 * @Version: 1.0
 */
public interface AuthService {

	/**
	 * @Description: 过滤方法
	 * @Param authDTO: 网关上下文
	 * @return: String
	 * @Author: wmh
	 * @Date: 2023/8/3 18:12
	 */
	String apply(AuthDTO authDTO);

}

返回值可以定义为统一返回值(R)等,为了演示方便,就返回字符串了

AuthTokenServiceImpl:

import cn.hutool.core.util.StrUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;

/**
 * @Author: wmh
 * @Description: token校验
 * @Date: 2023/8/3 18:21
 * @Version: 1.0
 */
@Slf4j
@Order(0)
@Service
public class AuthTokenServiceImpl implements AuthService {

	/**
	 * @Description: 验证token
	 * @Param authDTO: 网关上下文
	 * @return: com.norinaviation.atm.common.base.data.R
	 * @Author: wmh
	 * @Date: 2023/8/3 19:31
	 */
	@Override
	@SneakyThrows
	public String apply(AuthDTO authDTO) {
		String tokenHeader = authDTO.getHeaders().getFirst(CommonConstant.X_TOKEN);
		if (StrUtil.isBlank(appId)) {
			return "appId不能为空";
		}
		if (StrUtil.isBlank(tokenHeader)) {
			return "TOKEN不能为空";
		}
		JWT jwt = JWTUtil.parseToken(tokenHeader);
		boolean verifyKey = jwt.setKey(CommonConstant.JWT_TOKEN.getBytes()).verify();
		// 验证token是否正确
		if (!verifyKey) {
			log.info("appId:{}, TOKEN auth fail, TOKEN:{}", appId, tokenHeader);
			return "TOKEN认证失败";
		}
		boolean verifyTime = jwt.validate(0);
		// 验证token是否过期
		if (!verifyTime) {
			log.info("appId:{}, TOKEN expired, TOKEN:{}", appId, tokenHeader);
			return "TOKEN已过期";
		}
		return "success";
	}

}

AuthSignServiceImpl:

import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;
/**
 * @Author: wmh
 * @Description: 验签校验
 * @Date: 2023/8/3 18:24
 * @Version: 1.0
 */
@Slf4j
@Order(1)
@Service
public class AuthSignServiceImpl implements AuthService {

	/**
	 * @Description: 验证签名
	 * @Param authDTO: 网关上下文
	 * @return: Stirng
	 * @Author: wmh
	 * @Date: 2023/8/3 19:30
	 */
	@Override
	@SneakyThrows
	public Stirng apply(AuthDTO authDTO) {
		// 签名逻辑,业务代码就不公开了
		return "success";
	}

}

AuthFactory:

import cn.hutool.core.util.ObjectUtil;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * @Author: wmh
 * @Description: 权限工厂
 * @Date: 2023/8/7 15:54
 * @Version: 1.0
 */
@Component
public class AuthFactory implements ApplicationContextAware {

	/**
	 * 过滤方式
	 */
	private List<AuthService> authFilters = new ArrayList<>();

	/**
	 * 获取应用上下文并获取相应的接口实现类
	 * @param applicationContext
	 * @throws BeansException
	 */
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		// 获取实现类
		Map<Integer, AuthService> authServiceMap = new HashMap<>();
		applicationContext.getBeansOfType(AuthService.class).values().stream().forEach(authService -> {
			if (ObjectUtil.isNull(authService.getClass().getAnnotation(Order.class))) {
				authServiceMap.put(CommonConstant.DEFAULT_ORDER, authService);
			}
			else {
				authServiceMap.put(authService.getClass().getAnnotation(Order.class).value(), authService);
			}
		});
		// 根据order排序
		authServiceMap.entrySet().stream().sorted(Comparator.comparing(e -> e.getKey())).forEach(map -> {
			authFilters.add(map.getValue());
		});
	}

	/**
	 * @Description: 是否全部符合过滤条件
	 * @Param authDTO: 网关上下文
	 * @return: String
	 * @Author: wmh
	 * @Date: 2023/8/3 19:27
	 */
	public String apply(AuthDTO authDTO) {
		for (AuthService filter : authFilters) {
			String str = filter.apply(authDTO);
			if (!StrUtil.equals(str, "success")) {
				return str;
			}
		}
		return "success";
	}

}

AuthDTO:

import lombok.Data;
import org.springframework.http.HttpHeaders;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

/**
 * @Author: wmh
 * @Description: 网关上下文
 * @Date: 2023/8/3 19:09
 * @Version: 1.0
 */
@Data
public class AuthDTO {

	/**
	 * cache headers
	 */
	private HttpHeaders headers;

	/**
	 * cache json body
	 */
	private String cacheBody;

	/**
	 * cache formdata
	 */
	private MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();

}

此类为gateway网关需要,只展示使用过滤链的代码块

AuthGatewayFilterFactory:

/**
 * @Author: wmh
 * @Description: 权限校验过滤器
 * @Date: 2023/8/3 19:15
 * @Version: 1.0
 */
@Slf4j
@Component
public class AuthGatewayFilterFactory extends AbstractGatewayFilterFactory {

	@Autowired
	private AuthFactory authFactory;

	@Override
	public GatewayFilter apply(Config config) {
		return (exchange, chain) -> {
			ServerHttpRequest serverHttpRequest = exchange.getRequest();
			...
				// 获取request body
				GatewayContext gatewayContext = exchange.getAttribute(GatewayContext.CACHE_GATEWAY_CONTEXT);
				AuthDTO authDTO = new AuthDTO();
				authDTO.setHeaders(gatewayContext.getHeaders());
				authDTO.setCacheBody(gatewayContext.getCacheBody());
				authDTO.setFormData(gatewayContext.getFormData());
				// 验证
				String strr = authFactory.apply(authDTO);
			...
			return chain.filter(exchange);
		};
	}

}

Gateway相关:SpringCloud-Gateway实现网关_springcloud配置网关_W_Meng_H的博客-CSDN博客网关作为流量的入口,常用的功能包括路由转发、权限校验、限流等Spring Cloud 是Spring官方推出的第二代网关框架,由WebFlux+Netty+Reactor实现的响应式的API网关,它不能在传统的servlet容器工作,也不能构建war包。基于Filter的方式提供网关的基本功能,例如说安全认证、监控、限流等。_springcloud配置网关https://blog.csdn.net/W_Meng_H/article/details/129775851

CommonConstant(常量类):

/**
 * @Author: wmh
 * @Description: 常用变量
 * @Date: 2023/3/30 10:29
 * @Version: 1.0
 */
@Component
public class CommonConstant {

	// JWT密钥
	public static String JWT_TOKEN;

	// 请求头中的token
	public static final String X_TOKEN = "X-TOKEN";

	// 请求头中的签名
	public static final String X_SIGN = "X-SIGN";

	// 请求头中的appId
	public static final String X_APPID = "X-APPID";

	// 请求头中的时间戳
	public static final String X_TIMESTAMP = "X-TIMESTAMP";

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/894944.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解决@MapKey is required

问题复现&#xff1a; 出现原因&#xff1a; 因为使用了mybatisX插件&#xff0c;导致检查报错mapkey is required 当我们在mapper接口中产生错误&#xff0c;提示MapKey is required 时 解决方案&#xff1a; 1、关闭mybatis的检查&#xff0c;ctrlalts打开setting&#x…

ATFX汇评:英国7月零售销售年率大降,GBPUSD仍未升破1.3000

ATFX汇评&#xff1a;7月季调后零售销售年率&#xff0c;最新值-3.2%&#xff0c;前值-1.6%&#xff0c;降幅扩大&#xff1b;7月季调后核心零售销售年率&#xff0c;最新值-3.4%&#xff0c;前值-1.6%&#xff0c;降幅扩大。零售销售综合衡量除服务业外包括所有主要从事零售业…

Quest 2积分榜发布,快来查看你的排名吧,附上最新规则解读

在Quest 2发布时&#xff0c;Sui Network中文区发布了《详解Quest 2积分与奖励规则》带领大家解读活动规则。经过漫长而又焦急的等待&#xff0c;终于迎来了Quest 2积分榜的发布。与此同时&#xff0c;活动信息及规则也有了些许调整。 快前往Quest网站&#xff0c;查看你的排名…

HttpClint 项目中使用

大家好 , 我是苏麟 , 今天带来一个HTTP通信库 HttpClient . HttpClient是Apache Jakarta Common 下的子项目&#xff0c;可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包 . HttpClient的功能包括但不限于 1.模拟浏览器发送HTTP请求&#xff0c;发送…

echarts地图 省-市-县

// 直接用就行&#xff0c;已经是组件了 // 数据来源地址 http://datav.aliyun.com/portal/school/atlas/area_selector#&lat31.769817845138945&lng104.29901249999999&zoom4 // 例面的china.geo.json文件见https://geo.datav.aliyun.com/areas_v3/bound/100000_…

将vue项目通过electron打包成windows可执行程序

将vue项目打包成windows可执行程序 1、准备好dist将整个项目打包 npm run build2、安装electron依赖 npm install electron --save-dev npm install electron-packager --save-dev"electron": "^13.1.4", "electron-packager": "^15.2.0…

【Unity】坐标转换经纬度方法(应用篇)

【Unity】坐标转换经纬度方法&#xff08;应用篇&#xff09; 解决地图中经纬度坐标转换与unity坐标互转的问题。使用线性变换的方法&#xff0c;理论上可以解决小范围内所以坐标转换的问题。 之前有写过[Unity]坐标转换经纬度方法&#xff08;原理篇),在实际使用中&#xff0c…

外卖福利来了,以后都10元以下了

扫最后面的二维码注册&#xff0c;收藏起来&#xff0c;是个网页 使用方法&#xff1a; 纯订单 不需要评价 消费反馈 需要上传评价的截图 没要求的最少一张照片 有要求的按要求 看清美团还是饿了么 不能夸平台 美团不能修好评价 饿了么可以改一下

linux学习(文件描述符)[12]

输出重定向 本质在OS内部&#xff0c;更改fd对应内容的指向 #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>//myfile helloworld //int main(int argc,…

MySQL语法及常用数据类型

一、SQL语言概述 对数据库进行查询和修改操作的语言叫做SQL。SQL的含义就是结构化查询语言&#xff08;Structured Query Language&#xff09;。SQL包含以下4个部分&#xff1a; 1、数据定义语言&#xff08;DDL&#xff09;&#xff1a;DROP、CREATE、ALTER等语句&#xff…

这些选品神器,跨境卖家都在用

相信许多跨境电商商家至今不懂得如何选品&#xff0c;不会选&#xff1f;选什么类目&#xff1f;在哪选&#xff1f; 今天给大家整理一波实用选品工具&#xff0c;赶紧来码住。 1、TikTok 在国外流行着这么一句话:“TikTok mademe buyit”。 TikTok有超过 20亿的流量&#x…

ReentrantLock源码解析

定义 可重入锁&#xff0c;对于同一个线程可以重复获得此锁。分为FailLock和NonfairLock。 加锁就是将exclusiveOwnerThread设置为当前线程&#xff0c;且将status加一&#xff0c;解锁就status-1&#xff0c;且exclusiveOwnerThread设置为null。 公平锁&#xff1a;根据先来后…

C# Linq源码分析之Take (三)

概要 本文在前两篇Take源码分析的基础上&#xff0c;着重分析Range参数中有倒数的情况&#xff0c;即分析TakeRangeFromEndIterator的源码实现。 源码及分析 TakeRangeFromEndIterator方法用于处理Range中的开始和结束索引存在倒数的情况。该方法位于Take.cs文件中。通过yie…

Android4:约束布局

创建项目My Constraint Layout 一般创建项目之后activity_main.xml文件默认就是采用约束布局&#xff0c;如&#xff1a; <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayoutxmlns:android"http:…

FastDFS文件管理知识点+案例分析

一 介绍FastDFS 原理 FastDFS开源分布式文件系统由C语言编写实现, 可以通过专有API访问&#xff0c;目前提供了C、Java和PHP API。 FastDFS是一个开源的轻量级分布式文件系统&#xff0c;它对文件进行管理&#xff0c;功能包括&#xff1a;文件存储、文件同步、文件访问&#x…

scala中json4s 使用详解

预备知识 json4s的数据结构AST (Abstract Syntax Tree)。 sealed abstract class JValue case object JNothing extends JValue // zero for JValue case object JNull extends JValue case class JString(s: String) extends JValue case class JDouble(num: Double) extend…

企业需求如何精准对接科研院校科技成果?

一系列科技成果转化相关政策、法律法规的出台&#xff0c;正在破除高校科技成果转化机制上的桎梏。企业科技创新的需求也越来越大&#xff0c;也充分意识到与高校合作对于推动企业发展的重要性&#xff0c;对接科技成果的热情高涨&#xff0c;合作越来越频繁。但是也存在不成功…

SpringBoot 的 RedisTemplate、Redisson

一、Jedis、Lettuce、Redisson的简介 优先使用Lettuce&#xff0c; 需要分布式锁&#xff0c;分布式集合等分布式的高级特性&#xff0c;添加Redisson结合使用。 对于高并发&#xff0c;1000/s的并发&#xff0c;数据库可能由行锁变成表锁&#xff0c;性能下降会厉害。 1.1、…

linux中ubuntu安装hashcat方法以及使用GPU破解

一、linux安装hashcat git clone https://github.com/hashcat/hashcat.git make make install二、安装驱动 驱动版本安装大全&#xff1a;https://developer.nvidia.com/cuda-toolkit-archive 查看自己显卡选择对应的版本&#xff0c;根据下面命令无脑安装就行了 wget https:/…

誉天华为数通Datacom HCIE认证课程

作为当前网络领域最具含金量的认证之一&#xff0c;华为Datacom HCIE认证不仅是网络工程师们技术能力的证明&#xff0c;也是未来行业趋势的风向标。 尽管经历了几度版本更迭、考题变化&#xff0c;但是誉天一直紧跟技术发展趋势&#xff0c;在专业领域和教学内容上始终与当前的…