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

news/2024/7/23 11:31:21 标签: 设计模式, java, 开发语言

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

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

        类图:

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

AuthTokenServiceImpl:Token验证过滤器

AuthSignServiceImpl:签名验证过滤器

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

AuthDTO:过滤器所需要的参数

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

AuthService:

java">/**
 * @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:

java">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:

java">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:

java">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:

java">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:

java">/**
 * @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(常量类):

java">/**
 * @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.niftyadmin.cn/n/4950518.html

相关文章

leetcode做题笔记87扰乱字符串

使用下面描述的算法可以扰乱字符串 s 得到字符串 t &#xff1a; 如果字符串的长度为 1 &#xff0c;算法停止如果字符串的长度 > 1 &#xff0c;执行下述步骤&#xff1a; 在一个随机下标处将字符串分割成两个非空的子字符串。即&#xff0c;如果已知字符串 s &#xff0c…

【第四章 字符串part02】

28. 实现 strStr() 题目 BF算法 public int strStr(String s, String p) {// 输入&#xff1a;haystack "sa", needle "ss"//输出&#xff1a;0// bf算法int sLen s.length();int pLen p.length();for (int i 0; i < sLen-pLen1; i) {if(isEqu…

代码随想录 (二)链表

链表 二 移除链表元素 1 没有头结点 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next)…

html流光按钮

出处bilibili猫咪爱狗 <!DOCTYPE html> <html><head><style>body {/*内容居中&#xff0c;背景色*/height: 100vh;display: flex;justify-content: center; align-items: center;background-color: #000;}a { /*水平垂直居中*/position: re…

智能可穿戴:探索未来的无人之境

智能可穿戴&#xff1a;探索未来的无人之境 目录 引言智能可穿戴的历史与现状智能可穿戴的下一个蓝海&#xff1a;概念与理论市场展望&#xff1a;无人之境技术挑战与机遇结论 1. 引言 在科技的洪流中&#xff0c;智能可穿戴设备脱颖而出&#xff0c;以其便捷性、个性化和智…

Java Map、JSONObject、实体类互转

文章目录 前言Map、JSONObject、实体类互转 前言 使用库 com.alibaba.fastjson2&#xff0c;可完成大部分JSON转换操作。 详情参考文章: Java FASTJSON2 一个性能极致并且简单易用的JSON库 Map、JSONObject、实体类互转 import com.alibaba.fastjson2.JSON; import com.alib…

探索短视频小程序/小年糕

短视频小程序的兴起&#xff0c;为创作者提供了一个全新的平台&#xff0c;让他们能够以更专业的方式展现自己的作品。这种创作形式不仅要求作品内容足够精彩还需要有深度的思考和逻辑性的呈现。本文将探索短视频小程序的专业与深度的创作之道&#xff0c;帮助创作者更好地发挥…

Linux—LVM基础

Linux—LVM 一、什么是LVM二、LVM名词解释三、LVM的写入模式四、LVM的工作原理五、LVM的优缺点六、创建PV/VG/LV的方法补充说明 一、什么是LVM LVM&#xff08;Logical Volume Manager&#xff09;&#xff0c;即逻辑卷管理&#xff0c;是Linux环境下对磁盘分区进行管理的一种…