You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何限制网站仅允许已认证IP地址访问

嘿,这个需求在SaaS场景里太常见了,我来给你拆解成清晰的步骤,帮你快速落地,不用慌!

整体核心思路

你的需求本质是双重访问控制:先确认请求来自「已认证的系统」,再校验请求的IP在数据库维护的白名单内。我们要把这个校验逻辑放在请求到达业务代码之前的拦截层(比如后端中间件或者API网关),这样能最大程度减少无效请求对业务的影响。

具体实现步骤拆解

1. 先搞定数据库表设计

首先需要一张IP白名单表,用来存储允许访问的IP,建议关联到你的「已认证系统」表(比如每个系统可以绑定多个IP):

CREATE TABLE ip_whitelist (
    id INT AUTO_INCREMENT PRIMARY KEY,
    allowed_ip VARCHAR(45) NOT NULL UNIQUE, -- 支持IPv4/IPv6,IPv6最长是39字符,45足够
    system_id INT NOT NULL, -- 关联你的已认证系统表ID
    description VARCHAR(255) DEFAULT '', -- 可选:备注这个IP对应的系统用途
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (system_id) REFERENCES authenticated_systems(id)
);

如果你的场景是全局IP白名单(只要IP在名单里就允许已认证系统访问),也可以简化表结构,去掉system_id,直接存允许的IP即可。

2. 关键:获取请求的真实IP

这里要注意!如果你的SaaS应用部署在反向代理(比如Nginx、Cloudflare)后面,直接取请求的原始IP会拿到代理服务器的IP,而不是真实客户端的IP。所以要从请求头里取真实IP:

  • 常用的请求头:X-Forwarded-For、X-Real-IP
  • 注意:如果有多层代理,X-Forwarded-For是逗号分隔的IP列表,第一个就是真实客户端IP

3. 编写请求拦截校验逻辑

把校验逻辑做成全局中间件(所有请求都要经过),步骤如下:

  • 第一步:提取请求的真实IP
  • 第二步:验证请求的系统身份(比如校验请求头里的Authorization: Bearer <API_KEY>,查你的已认证系统表确认密钥有效)
  • 第三步:根据已认证的system_id,查询ip_whitelist表,看该IP是否在这个系统的允许列表内
  • 第四步:如果校验不通过,直接返回403 Forbidden,拒绝后续请求

4. 性能优化(可选但推荐)

如果你的请求量很大,每次校验都查数据库会有性能瓶颈,建议把IP白名单缓存到Redis里:

  • 定时从数据库同步白名单到Redis(比如每分钟同步一次)
  • 校验时先查Redis,不存在再查数据库,提升响应速度
代码示例(两种常见后端框架)

Node.js + Express 示例

const express = require('express');
const mysql = require('mysql2/promise');
const app = express();

// 数据库连接配置(实际项目建议用连接池)
const dbConfig = {
  host: 'your-db-host',
  user: 'your-db-user',
  password: 'your-db-pass',
  database: 'your-db-name'
};

// 全局中间件:IP白名单校验
app.use(async (req, res, next) => {
  try {
    // 1. 获取真实IP
    const realIp = req.headers['x-forwarded-for']?.split(',')[0]?.trim() || req.headers['x-real-ip']?.trim() || req.ip;
    
    if (!realIp) {
      return res.status(403).json({ error: '无法获取请求IP' });
    }

    // 2. 校验系统身份(这里示例用API_KEY,实际根据你的认证方式调整)
    const apiKey = req.headers['authorization']?.split(' ')[1];
    if (!apiKey) {
      return res.status(401).json({ error: '缺少系统认证信息' });
    }

    const connection = await mysql.createConnection(dbConfig);
    // 查已认证系统
    const [systems] = await connection.execute('SELECT id FROM authenticated_systems WHERE api_key = ?', [apiKey]);
    if (systems.length === 0) {
      await connection.end();
      return res.status(401).json({ error: '无效的系统认证信息' });
    }
    const systemId = systems[0].id;

    // 3. 校验IP是否在白名单内
    const [whitelist] = await connection.execute('SELECT * FROM ip_whitelist WHERE allowed_ip = ? AND system_id = ?', [realIp, systemId]);
    await connection.end();

    if (whitelist.length === 0) {
      return res.status(403).json({ error: 'IP不在允许访问列表内' });
    }

    // 校验通过,继续处理请求
    next();
  } catch (err) {
    console.error('校验出错:', err);
    return res.status(500).json({ error: '服务器内部错误' });
  }
});

// 你的业务路由
app.get('/api/your-service', (req, res) => {
  res.json({ message: '访问成功!' });
});

app.listen(3000, () => {
  console.log('服务器启动在3000端口');
});

Python + Django 示例

先自定义中间件ip_whitelist_middleware.py:

from django.http import JsonResponse
from django.db import connection
from django.utils.deprecation import MiddlewareMixin

class IPWhitelistMiddleware(MiddlewareMixin):
    def process_request(self, request):
        # 1. 获取真实IP
        def get_real_ip(req):
            x_forwarded_for = req.META.get('HTTP_X_FORWARDED_FOR')
            if x_forwarded_for:
                return x_forwarded_for.split(',')[0].strip()
            return req.META.get('HTTP_X_REAL_IP') or req.META.get('REMOTE_ADDR')
        
        real_ip = get_real_ip(request)
        if not real_ip:
            return JsonResponse({'error': '无法获取请求IP'}, status=403)
        
        # 2. 校验系统身份(示例用API_KEY,实际调整)
        api_key = request.META.get('HTTP_AUTHORIZATION', '').split(' ')[-1]
        if not api_key:
            return JsonResponse({'error': '缺少系统认证信息'}, status=401)
        
        # 查询已认证系统
        with connection.cursor() as cursor:
            cursor.execute("SELECT id FROM authenticated_systems WHERE api_key = %s", [api_key])
            system = cursor.fetchone()
            if not system:
                return JsonResponse({'error': '无效的系统认证信息'}, status=401)
            system_id = system[0]
            
            # 3. 校验IP白名单
            cursor.execute("SELECT * FROM ip_whitelist WHERE allowed_ip = %s AND system_id = %s", [real_ip, system_id])
            whitelist_entry = cursor.fetchone()
            if not whitelist_entry:
                return JsonResponse({'error': 'IP不在允许访问列表内'}, status=403)
        
        # 校验通过,继续处理
        return None

然后在settings.py里注册中间件:

MIDDLEWARE = [
    # ... 其他中间件
    'your_app.ip_whitelist_middleware.IPWhitelistMiddleware',
]
额外注意点
  • 如果需要支持CIDR网段(比如允许192.168.1.0/24整个网段),可以用数据库的IP范围查询,或者在代码里用专门的IP处理库(比如Node.js的ip库,Python的ipaddress模块)来判断IP是否在网段内。
  • 一定要做好日志记录:记录每个被拒绝的请求的IP、系统认证信息、时间,方便后续排查问题。

内容的提问来源于stack exchange,提问作者Gans

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:18:19