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

        过滤器模式(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";

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值