如何不使用htaccess限制Staging子域名访问?(PHP5.6/Apache/CentOS7)
最佳实现方案:基于Apache+PHP+MySQL的预发布环境IP白名单限制
针对你的需求,最佳方案是在Apache层面通过mod_rewrite将所有请求(包括静态资源)转发到一个PHP脚本进行IP校验,这样既能实现MySQL动态IP白名单,又能覆盖所有资源的访问控制——完美解决你之前遇到的静态资源不受限问题。下面是具体的实现步骤:
1. 配置Apache虚拟主机(替代.htaccess)
因为你不想用.htaccess,直接在Apache的虚拟主机配置文件(比如/etc/httpd/conf.d/dev.example.com.conf)中添加规则,确保所有请求先经过IP校验脚本:
<VirtualHost *:80> ServerName dev.example.com DocumentRoot /var/www/dev.example.com/public # 启用mod_rewrite模块(确保已在httpd.conf中开启) RewriteEngine On # 排除校验脚本本身,避免循环请求 RewriteCond %{REQUEST_URI} !^/ip-check.php$ # 将所有请求转发到ip-check.php,携带原请求路径 RewriteRule ^(.*)$ /ip-check.php?request_uri=$1 [L] </VirtualHost>
配置完成后重启Apache生效:
systemctl restart httpd
2. 编写IP校验脚本(ip-check.php)
在你的网站根目录创建ip-check.php,负责连接MySQL校验IP、转发合法请求或返回403:
<?php // 1. 数据库连接配置(根据你的实际信息修改) $dbHost = 'localhost'; $dbUser = 'your_db_user'; $dbPass = 'your_db_password'; $dbName = 'your_db_name'; $conn = mysqli_connect($dbHost, $dbUser, $dbPass, $dbName); if (!$conn) { die('数据库连接失败: ' . mysqli_connect_error()); } // 2. 获取用户真实IP(支持反向代理场景) $userIp = $_SERVER['REMOTE_ADDR']; // 如果有反向代理,优先取X-Forwarded-For(注意:需确保代理服务器正确设置该头) if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { $userIp = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0]; $userIp = trim($userIp); } // 3. 从MySQL查询IP是否在白名单(假设表名为allowed_ips,字段为ip_address) $query = "SELECT ip_address FROM allowed_ips WHERE ip_address = ?"; $stmt = mysqli_prepare($conn, $query); mysqli_stmt_bind_param($stmt, 's', $userIp); mysqli_stmt_execute($stmt); mysqli_stmt_store_result($stmt); if (mysqli_stmt_num_rows($stmt) > 0) { // IP合法,转发原请求 $requestUri = isset($_GET['request_uri']) ? $_GET['request_uri'] : ''; $filePath = $_SERVER['DOCUMENT_ROOT'] . '/' . $requestUri; // 检查目标文件是否存在 if (file_exists($filePath) && is_file($filePath)) { // 返回正确的MIME类型,确保静态资源正常加载 $mimeType = mime_content_type($filePath); header("Content-Type: $mimeType"); readfile($filePath); exit; } else { // 文件不存在,返回404 http_response_code(404); echo '404 Not Found'; exit; } } else { // IP非法,返回403禁止访问 http_response_code(403); echo '403 Forbidden: 你无权访问该预发布环境'; exit; } // 清理资源 mysqli_stmt_close($stmt); mysqli_close($conn); ?>
3. 性能优化建议
如果预发布环境访问量较大,每次请求都查数据库会影响性能,建议添加缓存机制:
// 新增缓存逻辑:将IP列表缓存到文件,5分钟更新一次 $cacheFile = '/tmp/allowed_ips.cache'; $cacheExpiry = 300; // 缓存有效期(秒) if (file_exists($cacheFile) && (time() - filemtime($cacheFile)) < $cacheExpiry) { // 从缓存读取IP列表 $allowedIps = unserialize(file_get_contents($cacheFile)); } else { // 从数据库读取并更新缓存 $query = "SELECT ip_address FROM allowed_ips"; $result = mysqli_query($conn, $query); $allowedIps = []; while ($row = mysqli_fetch_assoc($result)) { $allowedIps[] = $row['ip_address']; } file_put_contents($cacheFile, serialize($allowedIps)); } // 校验IP是否在缓存列表中 if (in_array($userIp, $allowedIps)) { // 放行逻辑... }
为什么这个方案更优?
- 覆盖所有资源:不管是PHP页面还是图片、JS/CSS静态文件,都会经过IP校验,彻底解决你之前的漏洞
- 动态更新IP:直接修改MySQL表中的IP即可生效,无需重启Apache或修改配置文件
- 避免.htaccess:完全符合你不使用.htaccess的要求
内容的提问来源于stack exchange,提问作者TStackOverflow
相关产品推荐
相关产品推荐

