⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 blog.csdn.net/andyLyysh 「珍朱(珠)奶茶」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

前言

在项目开发中,我们多少都会遇到要对请求访问IP做限制,允许哪些IP是可以访问系统。对于前后分离项目有两种方案,第一种是在Nginx服务中进行配置IP白名单,第二种是项目接口中进行白名单控制,例如在spring boot接口中进行白名单限制。

方案一:Nginx服务器中配置IP白名单限制

如果想在nginx做IP白名单限制访问,需要使用两个关键词,allow和deny;在nginx中,allow和deny是必须结合使用。

  • allow: 表示允许访问,即白名单;
  • deny: 表示禁止访问,即黑名单。

allow和deny可以配置http、server和location模块中。

注意:allow必须放在deny前面,否则会无效

详细案例如下

location模块:

server {
listen 8059;
server_name xxx.xxx.com;
charset utf-8;

location /api {
allow 192.168.183.89;
deny all;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:9659/api;

proxy_read_timeout 259200;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}

location /manage {
allow 192.168.183.89;
deny all;
.......
}
......
}

server模块:

server {
listen 8059;
server_name xxx.xxx.com;
charset utf-8;

allow 192.168.29.36;
allow 192.168.30.26;
......
deny all;

location /api {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:9659/api;

proxy_read_timeout 259200;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
}

http模块:

http {
include mime.types;
default_type application/octet-stream;
charset utf-8,gbk;
client_max_body_size 1024m;
client_body_buffer_size 300k;

sendfile on;
tcp_nopush on;

#keepalive_timeout 0;
keepalive_timeout 65;

fastcgi_connect_timeout 3000;
fastcgi_send_timeout 3000;
fastcgi_read_timeout 3000;

allow 192.168.56.92;
allow 192.168.89.129;
......
deny all;

server {
listen 8059;
server_name xxx.xxx.com;
charset utf-8;

.....
}
}

在Nginx配置IP白名单或黑名单,有个缺点就是每次配置完后都需要重启Nignx

方案二:在springboot中,自定义过滤器实现HandlerInterceptor

实现流程: 创建表 — 实现IP查询对比接口 — 自定义拦截器 — 获取请求IP — 对比IP是否在白名单中 — 请求返回

实现方式: Spring boot3 + Mysql8.0 + Mybatis-Flex

1、创建白名单管理表

CREATE TABLE `sh_sys_white_list` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`ip` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'ip地址',
`is_white` tinyint DEFAULT NULL COMMENT '是否白名单(1:是,2:否)',
`create_by` bigint DEFAULT NULL COMMENT '创建人',
`create_at` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` bigint DEFAULT NULL COMMENT '更新人',
`update_at` datetime DEFAULT NULL COMMENT '更新时间',
`deleted` tinyint DEFAULT NULL COMMENT '逻辑删除(0:正常,1:删除)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='白名单管理表';

自定义Mapper继承BaseMapper,自定义Service继承IBaservice、Impl继承BaseServiceImpl<Mapper, T>实现自定Service接口类。

package com.zhush.admin.service.impl;

import com.mybatisflex.core.query.QueryWrapper;
import com.zhush.admin.entity.SysWhiteList;
import com.zhush.admin.mapper.SysWhiteListMapper;
import com.zhush.admin.service.ISysWhiteListService;
import com.zhush.common.service.BaseServiceImpl;
import org.springframework.stereotype.Service;

import java.util.Objects;

import static com.zhush.admin.entity.table.SysWhiteListTableDef.SYS_WHITE_LIST;

/**
* @ClassName SysWhiteListServiceImpl
* @Description TODO
* @Author zhush
* @Date 2024/4/26 0026 14:20
**/
@Service
public class SysWhiteListServiceImpl extends BaseServiceImpl<SysWhiteListMapper, SysWhiteList> implements ISysWhiteListService {

/**
* 查找请求ip是否是白名单中
* @param ip
* @return
*/
@Override
public boolean getWhiteListByIp(String ip) {
QueryWrapper wrapper = QueryWrapper.create().where(SYS_WHITE_LIST.IP.eq(ip));
SysWhiteList sysWhiteList = this.mapper.selectOneByQuery(wrapper);
if (sysWhiteList != null && Objects.equals(sysWhiteList.getIsWhite(), 1)) {
return true;
} else {
return false;
}
}

}

2、自定义WhiteListHandlerInterceptor过滤器,实现HandlerInterceptor类

在自定义过滤中,重写preHandle方法,在preHandle方法中对比IP,具体实现如下:

package com.zhush.admin.handler;

import com.zhush.admin.service.ISysWhiteListService;
import com.zhush.common.enums.ResultCodeEnum;
import com.zhush.common.utils.IpUtils;
import com.zhush.common.utils.JacksonUtils;
import com.zhush.common.utils.Result;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import java.io.IOException;
import java.io.PrintWriter;

/**
* @ClassName WhiteListHandlerInterceptor
* @Description 白名单 处理器拦截器
* @Author zhush
* @Date 2024/4/26 0026 13:59
**/
public class WhiteListHandlerInterceptor implements HandlerInterceptor {

@Resource
private ISysWhiteListService whiteListService;

@Value("${zhush.white.enable}")
private boolean enable;

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (!enable) {
return true;
}
String ipAddr = IpUtils.getIpAddr(request);
boolean whiteListByIp = whiteListService.getWhiteListByIp(ipAddr);
if (whiteListByIp) {
return true;
} else {
result(response, JacksonUtils.toJSONString(Result.build("IP不在白名单内", ResultCodeEnum.ERROR)));
return false;
}
}

private void result(HttpServletResponse response, String result) {
PrintWriter writer = null;
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset=utf-8");
try {
writer = response.getWriter();
writer.println(result);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (writer != null) {
writer.close();
}
}
}
}

IpUtils工具类

package com.zhush.common.utils;

import jakarta.servlet.http.HttpServletRequest;

/**
* @ClassName IpUtils
* @Description ip获取工具类
* @Author zhush
* @Date 2024/4/26 0026 14:34
**/
public class IpUtils {

private static final String UNKNOWN = "unknown";

public static String getIpAddr(HttpServletRequest request) {
if (request == null) {
return UNKNOWN;
}

String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.isEmpty() || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.isEmpty() || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.isEmpty() || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.isEmpty() || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
String[] ips = ip.split(",");
return ips[0].trim();
}

}

3、自定义WebMvcConfig类,实现WebMvcConfigurer

在自定义的WebMvcConfig配置类中,注入WhiteListHandlerInterceptor拦截器。

package com.zhush.admin.config;

import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import com.zhush.admin.handler.WhiteListHandlerInterceptor;
import com.zhush.common.mapper.CustomerObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

/**
* @ClassName ZhushWebMvcConfig
* @Description TODO
* @Author zhush
* @Date 2024/2/3 0003 20:55
**/
@Configuration
public class ZhushWebMvcConfig implements WebMvcConfigurer {

@Bean
public WhiteListHandlerInterceptor whiteListHandlerInterceptor() {
return new WhiteListHandlerInterceptor();
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(whiteListHandlerInterceptor());
}

}

使用拦截器实现白名单的好处是不要重启任何服务器,只需要在往数据库表中添加白名单即可。

文章目录
  1. 1. 前言
  2. 2. 方案一:Nginx服务器中配置IP白名单限制
    1. 2.1. 详细案例如下
  3. 3. 方案二:在springboot中,自定义过滤器实现HandlerInterceptor
    1. 3.1. 1、创建白名单管理表
    2. 3.2. 2、自定义WhiteListHandlerInterceptor过滤器,实现HandlerInterceptor类
    3. 3.3. 3、自定义WebMvcConfig类,实现WebMvcConfigurer