本文目录导读:

- 核心原理(必读)
- 方案一:使用 Python Flask + iptables (适合Linux服务器或树莓派)
- 方案二:使用 Node.js + Express (跨平台,适合开发者和快速原型)
- 方案三:使用专用开源软件 (最强大、省心)
- 方案四:使用云服务或硬件厂商方案 (企业级)
- 关于 HTTPS (443端口) 的特殊处理
- 总结建议
搭建一个网页认证页(通常用于Wi-Fi热点、访客网络或企业内网),核心思路是使用 Portal 工具(如 Node.js、Python Flask、Nginx 等)创建一个重定向或拦截所有HTTP请求,并返回自定义登录页面的网关。
下面我为你梳理几种常见、好用且适合不同场景的搭建方法。
核心原理(必读)
无论用哪种工具,Portal认证的原理都是:
- 用户连上Wi-Fi,请求访问任意网站(如
www.baidu.com)。 - 网关/路由器 检测到该用户尚未认证,会将所有HTTP请求重定向(302重定向)到一个特定的IP地址(即你的Portal服务器)。
- 浏览器显示认证页,用户输入账号密码或点击“一键上网”。
- 认证成功,Portal服务器告知网关/路由器放行该用户,用户即可正常上网。
使用 Python Flask + iptables (适合Linux服务器或树莓派)
这是最灵活、最轻量级的方法,适合想要完全掌控流程的开发者。
准备环境 你需要一台 Linux 机器(如 Ubuntu/Debian),充当网关服务器。
编写 Portal 服务器代码 (app.py) 创建一个简单的 Flask 应用,提供一个登录页面。
from flask import Flask, request, redirect, render_template_string
app = Flask(__name__)
# 模拟已认证用户的IP列表 (实际应用应存数据库或缓存)
authenticated_ips = set()
# 认证页面 HTML (可以自定义样式)
LOGIN_PAGE = """
<!DOCTYPE html>
<html>
<head><title>Wi-Fi 认证</title></head>
<body>
<h2>欢迎使用免费Wi-Fi</h2>
<p>请输入手机号或点击按钮认证:</p>
<form method="POST" action="/login">
<input type="text" name="username" placeholder="手机号">
<button type="submit">一键上网</button>
</form>
</body>
</html>
"""
@app.route('/')
@app.route('/<path:path>')
def portal(path='/'):
# 获取客户端IP
client_ip = request.remote_addr
# 如果已认证,放行 (重定向到原始目标)
if client_ip in authenticated_ips:
target = request.args.get('url') or 'http://example.com'
return redirect(target)
# 未认证,显示认证页 (注意携带原始URL参数)
return render_template_string(LOGIN_PAGE, target_url=request.url)
@app.route('/login', methods=['POST'])
def login():
# 模拟认证: 将客户端IP加入白名单
client_ip = request.remote_addr
authenticated_ips.add(client_ip)
# 重定向到原始目标 (或默认网站)
target = request.form.get('target_url', 'http://example.com')
return redirect(target)
if __name__ == '__main__':
# 运行在0.0.0.0,端口8080
app.run(host='0.0.0.0', port=8080, debug=False)
设置 iptables 规则进行流量拦截 这是关键步骤:将所有HTTP (80端口) 和 HTTPS (443端口) 流量重定向到你的Portal服务器(假设你的服务器IP是 192.168.1.100,Portal端口是 8080)。
# 开启IP转发 (让这台机器成为路由器) echo 1 > /proc/sys/net/ipv4/ip_forward # 将发往80端口的流量重定向到8080 (Portal) iptables -t nat -A PREROUTING -i wlan0 -p tcp --dport 80 -j REDIRECT --to-port 8080 # 对于HTTPS (443),你需要生成自签名证书并通过HTTPS提供Portal,或者简单地将443也重定向到Portal的80端口 (不推荐,会报安全错误) # 更常见的做法是只重定向HTTP,因为用户第一次发起的是HTTP请求。
注意:wlan0 是你的Wi-Fi网卡接口,根据实际情况替换。
运行并测试
python3 app.py
用户连上Wi-Fi后,打开浏览器访问任意网站,应该就会被重定向到你的Web页面。
使用 Node.js + Express (跨平台,适合开发者和快速原型)
逻辑与方案一完全一致,只是换成了JavaScript。
初始化项目并安装依赖
mkdir portal-server && cd portal-server npm init -y npm install express
编写 server.js
const express = require('express');
const app = express();
const authenticatedIPs = new Set();
const PORTAL_PORT = 3000;
app.use(express.urlencoded({ extended: true }));
app.get('*', (req, res) => {
const clientIP = req.ip;
const targetUrl = req.query.url || 'http://example.com';
if (authenticatedIPs.has(clientIP)) {
// 已认证,放行
return res.redirect(targetUrl);
}
// 显示认证页面
res.send(`
<html>
<body>
<h2>欢迎使用免费Wi-Fi (Node.js Portal)</h2>
<form method="POST" action="/login">
<input type="hidden" name="target_url" value="${targetUrl}">
<input type="text" name="username" placeholder="请输入手机号">
<button type="submit">连接网络</button>
</form>
</body>
</html>
`);
});
app.post('/login', (req, res) => {
const clientIP = req.ip;
authenticatedIPs.add(clientIP);
const targetUrl = req.body.target_url || 'http://example.com';
res.redirect(targetUrl);
});
app.listen(PORTAL_PORT, '0.0.0.0', () => {
console.log(`Portal server running on port ${PORTAL_PORT}`);
});
运行并设置 iptables (与方案一相同)
node server.js # 然后同样需要配置 iptables 重定向 80 -> 3000
使用专用开源软件 (最强大、省心)
如果你不想从头写代码,可以使用成熟的Portal解决方案,它们通常集成了认证、计费、带宽控制等功能。
-
CoovaChilli (http://coova.org/CoovaChilli)
- 这是非常著名的Captive Portal引擎,常用于OpenWrt路由器或 Linux 服务器。
- 它自己处理网络层的重定向,你只需要提供一个Web页面(通过URL配置给它)。
- 搭建步骤:
- 安装
chilli。 - 配置
/etc/chilli.conf,指定你的Web服务器地址:uamserver http://你的IP/。 - 启动
chilli和你的Web服务器。
- 安装
- 优点:功能完整,支持UAM(用户自主管理),MAC地址认证等。
-
Node.js 的 captive-portal 库 (https://github.com/samuelcolvin/captive-portal)
一个专门用于创建Captive Portal的Node.js框架,包含了HTTP/HTTPS拦截逻辑,甚至能模拟Apple/Android检测页面。
-
OpenWrt 路由器 + LuCI Captive Portal
- 如果你的路由器刷了OpenWrt,可以直接安装
luci-app-captiveportal或wifidog。 - 配置简单,直接在路由器Web界面设置认证服务器地址即可。
- 如果你的路由器刷了OpenWrt,可以直接安装
使用云服务或硬件厂商方案 (企业级)
如果你不是自己练习,而是为了正式部署(如酒店、商场),建议使用现成的云Portal平台或商业路由器。
- 云Portal服务商:爱快(iKuai)、深信服、H3C 的云AC平台,你只需在路由器/AC中配置云Portal的URL,它们会提供完整的认证页面(短信认证、微信认证、会员认证)。
- 硬件厂商:购买支持Portal认证的企业路由器(如TP-Link ER系列、锐捷),配置非常简单,通常只需要开启“强制认证”并选择一个内置模板即可。
HTTPS (443端口) 的特殊处理
- 问题:当你重定向HTTPS流量时,浏览器会报“证书错误”或“连接不安全”,因为用户访问的是
https://www.baidu.com,但流量被转发到了你未加密的Portal服务器。 - 解决方案:
- 只重定向HTTP:这是最常见且最合适的做法,因为用户通常第一次请求是HTTP,或者浏览器会自动尝试HTTP,你只需保证Portal页面本身使用 HTTP 即可。
- 使用自签名或合法证书:你的Portal服务器绑定一个域名(如
portal.yourcompany.com),并为其申请SSL证书,在iptables中,你需要将443端口重定向到Portal的443端口,并开启HTTPS,这是最正确的企业级做法。
总结建议
| 你的需求 | 推荐方案 | 难度 | 说明 |
|---|---|---|---|
| 学习技术原理 | Python/Node.js + iptables (方案一/二) | ⭐⭐⭐ | 手写代码,理解整个流程 |
| 快速搭建测试环境 | Node.js + iptables | ⭐⭐ | 开发效率高 |
| 树莓派/家用路由器 | CoovaChilli (方案三) | ⭐⭐⭐ | 功能稳定,配置简单 |
| 企业正式部署 | 云Portal服务 / 商业路由器 (方案四) | ⭐ | 最省心,提供技术支持 |
核心步骤总结:
- 编写一个返回登录页面的Web应用(Flask/Express)。
- 配置网关(iptables/路由器)将未认证用户的80端口流量重定向到你的Web应用。
- 处理登录,并在登录成功后,放行用户(通常是通过数据库标记或IP白名单)。
- 处理Apple/Android的Wi-Fi助手检测 (可选,但能提升用户体验)。
如果你在具体实施中遇到端口转发、防火墙或页面样式问题,可以进一步沟通。
标签: 网页认证页