网关认证,完成白名单功能

如何使用网关认证实现白名单功能,白名单就是相对于黑名单的一个概念,在网络访问中,白名单可以不需要验证直接进行操作

那么如何实现白名单的功能?

核心依赖添加

 <dependencies>
<!--网关-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--响应式编程-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
        </dependency>
<!--mybatis和数据库连接的依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.19</version>
        </dependency>
<!--mybatis依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.2</version>
        </dependency>

    </dependencies>

1.在数据库中添加白名单表


SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for finance_white
-- ----------------------------
DROP TABLE IF EXISTS `finance_white`;
CREATE TABLE `finance_white`  (
  `id` int(0) NOT NULL AUTO_INCREMENT,
  `path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '请求路径',
  `route_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '路由类型',
  `create_date` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `update_date` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
  `create_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '创建人',
  `update_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '修改人',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of finance_white
-- ----------------------------
INSERT INTO `finance_white` VALUES (1, '/login', '登陆', '2023-08-19 14:33:10', '2023-08-19 14:33:19', 'zhangsan', 'zhangsan ');

SET FOREIGN_KEY_CHECKS = 1;

数据表

 使用batis-x生成mapper、pojo、service

使用redis缓存白名单信息,可能需要redis的配置类

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate redisTemplateInit(RedisConnectionFactory redisConnectionFactory) {

        RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();

        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //设置序列化Key的实例化对象
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //设置序列化Value的实例化对象
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());

        /**
         *
         * 设置Hash类型存储时,对象序列化报错解决
         */
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        return redisTemplate;
    }
}

在过滤器中验证请求是否属于白名单,如果属于白名单直接进行放行,如果不在白名单内,拦截器将对请求进行拦截,并且返回403状态码,提醒访问者

public class LoginFilter implements GlobalFilter {
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    @Autowired
    private FinanceWhiteMapper whiteMapper;
    @Autowired
    private FinanceWhiteService whiteService;
    /**
     * 方法签名,表示一个用于网关过滤器的filter方法
     * @param exchange
     * ServerWebExchange:表示当前请求和响应的上下文对象,
     * 包含了与请求相关的信息(如请求头、请求体等)以及响应的操作(如设置响应头、发送响应等)
     * @param chain
     * GatewayFilterChain:表示过滤器链,
     * 通过调用该链的next方法来继续执行后续的过滤器或者转发到路由处理器进行请求处理
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange,
                             GatewayFilterChain chain) {
        //认证,(获得请求)
        ServerHttpRequest request = exchange.getRequest();

        /**
         * 通过调用getHeaders()方法可以获取到请求头(HttpHeaders)对象。
         * 然后,通过调用getFirst("token")方法
         * 获取到名为"token"的请求头的第一个值
         */
        //从请求头获取token
        String token = request.getHeaders().getFirst("token");
        //登陆path不需要进行验证(白名单:存放在配置文件或者redis中
        String path = request.getPath().toString();
        // ValueOperations<String, Object> opsForValue = redisTemplate.opsForValue();
        //在redis里面查询已经有的路径;大键white,小健path,如果查不到直接返回403,查到了就通过
        
        //,删redis,查数据库,存redis,匹配成功通过
        redisTemplate.opsForHash().delete("whitePath", "path");
        //查询数据库
        List<FinanceWhite> list1 = whiteService.list();
        String jsonStr = JSONUtil.toJsonStr(list1);
        //存redis
        redisTemplate.opsForHash().put("whitePath", "path",jsonStr);
        String s = (String) redisTemplate.opsForHash().get("whitePath", "path");
        JSONArray objects = JSONUtil.parseArray(s);
        List<FinanceWhite> list2 = JSONUtil.toList(objects, FinanceWhite.class);
//        boolean isHavePath=false;
        //匹配请求的路径是否是白名单,放行
        for (FinanceWhite financeWhite : list2) {
            if(path.equals(financeWhite.getPath())){
//                isHavePath=true;
                return chain.filter(exchange);
            }

        }


        //list从redis获取
        List<String> list=new ArrayList<>();
//        list.add(opsForValue.toString());
        list.add("/login");
        if(list.contains(path)){
            return chain.filter(exchange);
        }


        //认证不通过,无法获取token返回404forbidden
        if(StringUtils.isBlank(token) || !JWTUtil.verify(token,"woniu".getBytes())){
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.FORBIDDEN);
            return response.setComplete();
        }
        /**
         * 认证通过,直接放行
         */
            return chain.filter(exchange);

    }
}

为什么要先删除redis里面的白名单?

1.防止数据库里面的白名单发生变化,所以每次请求先删除白名单,然后访问数据库查询白名单信息,将数据库的白名单信息缓存到redis,再将redis的白名单path和请求对比

2.对比通过就成功放行,对比不通过,禁止放行

缺点是如果有大量访问,可能会导致数据库访问太大,导致宕机,所以接下来会采用响应式编程来解决白名单的访问

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值