如何给网关设计一款专属的权限控制「责任链设计模式」(1)
1.多条件流程判断 权限控制
2.ERP 系统 流程审批 总经理、人事经理、项目经理
3.Java 过滤器的底层实现 Filter
比如:在 Java 过滤器中客户端发送请求到服务器端,过滤会经过参数过滤、session 过滤、表单过滤、隐藏过滤、检测请求头过滤
网关权限控制责任链模式
===========
在网关作为微服务程序的入口,拦截客户端所有的请求实现权限控制 ,比如先判断 Api 接口限流、黑名单、用户会话信息拦截。
Api 接口限流→黑名单拦截→用户会话信息拦截
GatewayHandler 抽象角色
/**
@title: GatewayHandler
*/
public abstract class GatewayHandler {
/**
执行下一个 handler
*/
protected GatewayHandler nextGatewayHandler;
public void setNextGatewayHandler(GatewayHandler nextGatewayHandler) {
this.nextGatewayHandler = nextGatewayHandler;
}
//实现的 handler 处理方案 强制必须实现
public abstract void service();
protected void nextService() {
if (nextGatewayHandler != null)
// 指向下一关
nextGatewayHandler.service();
}
}
具体 Handler 实现
@Slf4j
@Component
public class CurrentLimitHandler extends GatewayHandler {
@Override
public void service() {
log.info("第一关 API 接口限流操作.....");
//指向下一关
nextService();
}
}
@Component
@Slf4j
public class BlacklistHandler extends GatewayHandler {
@Override
public void service() {
log.info("第二关 黑名单拦截.......");
//指向下一关
nextService();
}
}
@Component
@Slf4j
public class ConversationHandler extends GatewayHandler {
@Override
public void service() {
log.info("第三关 用户的会话信息拦截.......");
}
}
基于数据库实现
相关 SQL 语句
CREATE TABLE gateway_handler
(
ID
int(11) NOT NULL AUTO_INCREMENT COMMENT '主键 ID',
handler_name
varchar(32) DEFAULT NULL COMMENT 'handler 名称',
handler_id
varchar(32) DEFAULT NULL COMMENT 'handler 主键 id',
prev_handler_id
varchar(32) DEFAULT NULL,
next_handler_id
varchar(32) DEFAULT NULL COMMENT '下一个 handler',
PRIMARY KEY (ID
)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8 COMMENT='权限表';
-- Records of gateway_handler
INSERT INTO gateway_handler
VALUES ('16', 'Api 接口限流', 'currentLimitHandler', null, 'blacklistHandler');
INSERT INTO gateway_handler
VALUES ('17', '黑名单拦截', 'blacklistHandler', 'currentLimitHandler', 'conversationHandler');
INSERT INTO gateway_handler
VALUES ('18', '会话验证', 'conversationHandler', 'blacklistHandler', null);
Utils
=========
@Component
public class SpringUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
//获取 applicationContext
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
//通过 name 获取 Bean.
public static Object getBean(String name){
return getApplicationContext().getBean(name);
}
//通过 class 获取 Bean.
public static <T> T getBean(Class<T> clazz){
return getApplicationContext().getBean(clazz);
}
//通过 name,以及 Clazz 返回指定的 Bean
public static <T> T getBean(String name,Class<T> clazz){
return getApplicationContext().getBean(name, clazz);
}
}
GatewayHandlerService
=========================
/**
@title: GatewayHandlerService
*/
@Service
public class GatewayHandlerService {
@Autowired
private GatewayHandlerMapper gatewayHandlerMapper;
private GatewayHandler firstGatewayHandler;
/**
获取数据库第一个 handeler 封装
*/
public GatewayHandler getFirstGatewayHandler() {
if (firstGatewayHandler != null) {
return firstGatewayHandler;
}
//1.【第一个实体】
GatewayHandlerEntity firstGatewayHandlerEntity = gatewayHandlerMapper.getFirstGatewayHandler();
if(firstGatewayHandlerEntity==null){ return null; }
//2.【第一个 HandlerId】
String firstHhandlerId = firstGatewayHandlerEntity.getHandlerId();
//3.【第二个 HandlerId】
String secondHandlerId = firstGatewayHandlerEntity.getNextHandlerId();
//4.【第一个 bean 对象】
GatewayHandler firstGatewayHandler = SpringUtils.getBean(firstHhandlerId, GatewayHandler.class);
//5.【tmpHandler 为第一个 bean 对象】
GatewayHandler tmpHandler=firstGatewayHandler;
//如果下一个 HandlerId 不为 null,则继续
while (!StringUtils.isBlank(secondHandlerId)){
//6.【第二个 bean 对象】->11.【第三个 bean 对象】
GatewayHandler secondGatewayHandler = SpringUtils.getBean(secondHandlerId, GatewayHandler.class);
//7.【设置第一个 bean 对象的 next 为第二个 bean 对象】->12.【设置第二个 bean 对象的 next 为第三个 bean 对象】
tmpHandler.setNextGatewayHandler(secondGatewayHandler);
//8.【第二个实体】->13.【第三个实体】
GatewayHandlerEntity secondHandlerEntity = gatewayHandlerMapper.getByHandler(secondHandlerId);
if (secondHandlerEntity==null){ break; }
//9.【第三个 HandlerId】->14.【第四个 HandlerId】此时为 null,后面会退出循环
secondHandlerId=secondHandlerEntity.getNextHandlerId();
//10.【tmpHandler 为第二个 bean 对象】->15.【tmpHandler 为第三个 bean 对象】
tmpHandler=secondGatewayHandler;
}
//16.赋值
this.firstGatewayHandler=firstGatewayHandler;
//17.返回第一个 firstHandler 对象
return firstGatewayHandler;
}
}
数据库访问层
GatewayHandlerMapper
public interface GatewayHandlerMapper {
/**
获取第一个 GatewayHandler
*/
@Select("SELECT handler_name AS handlerName,handler_id AS handlerid ,prev_handler_id AS prevhandlerid ,next_handler_id AS nexthandlerid FROM gateway_handler WHERE prev_handler_id is null;;")
public GatewayHandlerEntity getFirstGatewayHandler();
@Select("SELECT handler_name AS handlerName,handler_id AS handlerid ,prev_handler_id AS prevhandlerid ,next_handler_id AS nexthandlerid FROM gateway_handler WHERE handler_id=#{handlerId}")
public GatewayHandlerEntity getByHandler(String handlerId);
}
Entity 层
@Data
public class GatewayHandlerEntity implements Serializable, Cloneable {
/**
主键 ID
*/
private Integer id;
/**
handler 名称
*/
private String handlerName;
/**
handler 主键 id
*/
private String handlerId;
/**
下一个 handler
*/
private String nextHandlerId;
}
Controller 层
/**
@title: HandlerController
*/
@RestController
public class HandlerController {
@Autowired
private GatewayHandlerService gatewayHandlerService;
@RequestMapping("/client")
public String client() {
GatewayHandler firstGatewayHandler = gatewayHandlerService.getFirstGatewayHandler();
firstGatewayHandler.service();
return "success";
}
}
相关配置信息
==========
版权 @须臾之余
https://my.oschina.net/u/3995125
application.yml
###服务启动端口号
server:
port: 8080
评论