
简介开源实现的Portal协议服务端程序基于Java技术栈编写面向网络运维人员与认证系统二次开发者。支持华为、H3C、锐捷、爱快等主流设备覆盖标准Portal、Portal V1/V2、CMCC等协议兼容PAP/CHAP认证提供一键认证、系统接入用户认证、外部Radius认证、微信认证、短信认证、动态密码等多样化接入方式适合园区网、酒店、校园网等场景部署。整个压缩包约52MB共1477个文件其中class与jar为编译后的核心逻辑与依赖库jsp/js/css构成管理界面xml/properties为配置项另有sql脚本、Tomcat启动/关闭脚本、shell/bat运维脚本及APK客户端目录结构完整便于直接部署或改造。框架采用SpringMVC、Spring、Mybatis、Shiro、Ehcache、quartz、jersey等主流组件代码组织清晰可作为学习Portal协议实现与Java Web整合开发的参考。目前已有1349人学习下载借助该源码可快速搭建测试环境理解认证报文交互流程并基于标准接口扩展第三方认证适合需要对接设备认证或搭建自研认证平台的技术人员。 做公共场所WiFi运营的人对OpenPortalServer这个名字应该不陌生。作为一个开源认证门户系统它的核心任务很明确把谁都能连的WiFi变成只有授权用户才能用的WiFi。用户连上热点后网关会把浏览器的HTTP请求强制重定向到门户页面用户在页面上输入账号密码或兑换码系统校验通过后才正式放行流量放行的同时还能附带完成限速、时长统计、在线用户管理等运营动作。我手上这套V3.3.5.6 Stable版本发布在2016年1月16日算得上当年这个项目稳定分支里的一个代表作。两年前接手一家小型园区WiFi改造项目时我拿它做了整套认证核心从测试到全量上线再到日常维护过程里走了不少弯路也沉淀了不少经验。这篇文档就把我从零部署到稳定运行的完整过程记录下来给准备做公共WiFi认证的朋友一个可参照的实操样本。1. 认证门户在WiFi网络里的定位为什么需要这么一套系统1.1 一条完整的公共WiFi认证链路拆解先还原一个最典型的现场。客人走进咖啡馆手机连上名为Cafe-FreeWiFi的热点此时设备从DHCP拿到的只是一个内网IP任何访问外网的请求都会被网关截住。他打开浏览器随便输入一个网址页面立刻跳转到一个登录门户上面写着请输入小票上的上网验证码。客人在收银台结账后获得一张印有8位验证码的小票输入验证码点击连接几秒后跳转到连接成功欢迎使用的页面这时再去刷视频、看网页都已经畅通无阻。这条链路拆开来看包含几个环节DHCP分配地址、DNS解析、HTTP请求触发重定向、认证页展示、凭证校验、网关放行、会话记账。OpenPortalServer承担的就是其中认证页展示凭证校验用户管理会话记账这一整块也就是从用户看到登录页开始到他被正式放行之间的所有逻辑。网关设备则负责最前端的重定向和最末端的流量放行两者通过一套约定好的UAMUniversal Access Method协议交互OpenPortalServer这边处理好之后通过后台回调接口通知网关这个用户已经被放行了。如果用打比方的方式理解网关像是商场门口的闸机OpenPortalServer就是闸机后面的核验台。闸机只管拦住人把每个人送到核验台面前核验台检查身份、登记信息、决定谁可以进、谁要延长时间然后通过对讲机通知闸机打开通道。这个分工保证了整个系统可以横向扩展——核验台效率不够了可以单独升级不需要动闸机反过来也一样。1.2 为什么选OpenPortalServer而不是商用或自研方案做选型的时候我实际上对比过三类方案。第一类是商用认证平台按AP数量或者用户数收费功能确实全但小园区的预算根本吃不住那个授权费用。第二类是自己用PHP或Python写一个简易门户做个数据库账号校验不难但要做到兑换码批量生成、定时段限速、RADIUS记账、在线踢人这一层开发工作量就不是一周两周能收尾的了。第三类就是OpenPortalServer这类成熟开源项目优势在于把运营场景里高频用到的功能都做成了现成模块社区里也有大量同类型部署案例可以参考。具体到V3.3.5.6 Stable这个版本我在选型时看中了几个点一是它和Coova Chilli这类网关组件的兼容性经过社区大量验证对接文档齐全二是管理后台的界面虽然朴素但功能分区清晰日常操作不需要依赖命令行三是它支持本地账号和外部RADIUS双通道认证意味着后期如果要接入更复杂的计费或统一认证平台不需要推倒重来。后来的运维实践也证明这个版本虽然发布时间早但该有的功能一个不少稳定性和资源占用表现都不错。2. 部署前的环境准备与选型清单2.1 硬件配置与软件栈选择OpenPortalServer本质上是一套PHPMySQL的Web应用因此它不挑硬件。以我这个园区约200个并发在线用户的规模为例一台双核CPU、2GB内存、40GB磁盘的服务器就够用了实际运行时CPU空闲率常年保持在90%以上。真正要注意的是数据库这一层。用户的认证请求、会话记录、兑换码库存都会落库数据库连接数如果不做缓冲用户集中接入的时段容易出现连接数已满的报错。我的做法是在应用和数据库之间保留一层连接缓冲把MySQL的max_connections从默认值调高到512同时给常用的session表和voucher表加上索引避免全表扫描拖慢认证响应。软件栈方面考虑到这是2016年的版本PHP 5.6分支和MySQL 5.5/5.6系列是它最舒服的运行环境。如果你的服务器系统比较新自带PHP 8.x我建议还是用Docker把旧环境隔离起来或者直接找一台跑老系统的机器省得在兼容性上花时间。Web服务器我用的是Nginx加PHP-FPM相比Apache并发能力更好配置也不复杂。需要注意PHP-FPM里的cgi.fix_pathinfo必须设为0这是Nginx解析PHP时的一个老坑不关掉容易被人利用构造恶意请求。2.2 网络拓扑与IP规划要点部署前先把IP规划做清楚后面能省掉大量排错时间。我当时的拓扑分成三个网段管理网段192.168.10.0/24专门放Portal服务器、数据库、运维终端用户网段172.16.20.0/24分配给WiFi客户端由网关上内置的DHCP服务统一分配外网则走网关的WAN口上行。认证网关放在用户网段和WAN之间同时连接管理网段这样它既能和Portal服务器内网通信也能直接把用户流量送出去。值得多说一句的是Portal服务器的地址一定要用固定IP不能走DHCP分配否则网关上的UAM回调地址会跟着漂移。我见过不止一次有人在这里踩坑——Portal服务器地址变了用户认证成功后网关找不到回调目标表现为认证页面能打开但输完密码就卡住。另外用户网段的DNS也要确认能被正确下发不少老设备在DNS解析失败时会导致重定向页面加载异常。3. 从零部署OpenPortalServer安装与网关联动3.1 源码部署的完整步骤把安装过程拆成一步步来方便照抄。以下命令基于Debian系Linux发行版其他系统请对应调整。# 1. 安装基础软件栈 apt-get update apt-get install -y nginx mysql-server php5-fpm php5-mysql php5-gd php5-curl # 2. 把OpenPortalServer源码解压到web目录 mkdir -p /var/www/html/openportal cd /var/www/html/openportal tar -zxvf /root/OpenPortalServer_V3.3.5.6_Stable.tar.gz# 3. 创建数据库并导入初始表结构 mysql -uroot -p CREATE DATABASE openportal DEFAULT CHARACTER SET utf8mb4; GRANT ALL PRIVILEGES ON openportal.* TO portallocalhost IDENTIFIED BY yourpassword; FLUSH PRIVILEGES; exit mysql -uportal -p openportal /var/www/html/openportal/database/install.sql# 4. 修改应用配置文件 vi /var/www/html/openportal/config/config.php配置文件中重点检查三块数据库连接信息主机、库名、账号、密码、系统对外访问的基础URL、以及和网关约定的共享密钥。共享密钥这一项千万别留默认值安装后第一件事就是改掉它。密钥不一致会导致网关和Portal之间无法正常通信认证逻辑直接失灵。# 5. 配置Nginx站点并重启服务 vi /etc/nginx/sites-available/openportal ln -s /etc/nginx/sites-available/openportal /etc/nginx/sites-enabled/ nginx -t systemctl restart nginx systemctl restart php5-fpm上传目录和日志目录要确保web用户有写权限否则兑换码导出和日志写入会报错。这一步如果忽略很容易在后期遇到功能按钮点了没反应的怪异问题实际上就是目录不可写错误信息又被日志记录逻辑吞掉了。3.2 与Coova Chilli网关的联动配置Portal服务起来了接下来要让网关把用户请求引导过来。我用的是Coova Chilli作为WiFi接入认证网关它有一个重定向参数专门指定Portal服务器地址。找一下chilli的配置文件通常是/etc/chilli.conf把以下几项改掉# chilli.conf 关键参数 uamserver http://192.168.10.10/openportal/index.php uamsecret your-shared-secret uamhomepage http://192.168.10.10/openportal/index.php coaport 3799这里uamserver就是认证页服务地址uamsecret必须和Portal配置里的共享密钥保持一致。改完之后重启chilli服务然后拿一台手机连上WiFi测试正常的话手机会自动弹出认证页面。如果手机没有弹出页面手动打开浏览器访问任意HTTP站点同样会触发重定向。3.3 首次进入管理后台必做的两件事浏览器访问Portal服务器的管理地址使用安装过程中创建的管理员账号登录。第一次登录后建议先做两件事一是修改管理员密码二是核对系统基础参数包括组织名称、时区、日期格式、默认会话时长。当时区不对的时候会产生一个很隐蔽的问题兑换码的有效期计算错位明明买了24小时券用户用了20小时就提示过期了。这类问题排查起来特别费劲所以基础参数一定要在开局阶段就检查到位。4. 核心功能实战认证、兑换码与限速4.1 本地账号与RADIUS双通道认证OpenPortalServer在认证环节支持两条路径。一条是纯本地账号管理员在后台手动创建用户设置密码、有效期、并发数、限速模板适合用户规模不大、运营动作简单的场景。另一条是走RADIUS协议对接外部认证服务器适合已经有统一账号体系的单位比如校园网账号、企业内部账号。我的园区一开始用的本地账号后期接入了统一认证平台切换时只需要在后台把认证源改成RADIUS填上RADIUS服务器地址和共享密钥用户侧完全无感知。两种方式各有适用场景。本地账号胜在零依赖不担心RADIUS服务器挂掉导致全网认证瘫痪RADIUS则赢在账号集中管理适合跨设备统一认证。如果条件允许我建议主用RADIUS、本地账号留作应急备份通道两边都配置好关键时刻能救急。切换认证源的操作在后台几分钟就能完成但要特别注意切换后一段时间内不要关闭旧通道因为在线用户的会话续期请求可能还在走旧的RADIUS服务器提前关掉会造成一批用户被动离线。4.2 兑换码批量生成与生命周期管理兑换码是公共WiFi运营里用得最频繁的功能。客人到店消费后收银台把小票上的验证码给客人客人输入后获得对应时长的上网权限。后台生成兑换码时可以设置多个参数有效期比如24小时、7天、30天、同时在线数防止一个码多个人同时使用、限速模板、码位长度和批次数量。我的习惯是一次生成500个码打印成A5小票盖一个店章分发到各个收银点。这里有个实操细节要提醒生成兑换码时尽量选择字母数字混合且排除易混淆字符像0和O、1和I这些直接去掉不然客人输错几次就会烦躁前台客服的解释成本很高。另外后台要定期清理已经过期的兑换码和用户会话虽然这个版本不会主动做自动清理但可以写一个cron脚本每周跑一次清理能明显降低数据库的膨胀速度。4.3 带宽限速与在线用户管控公共WiFi最怕有人开着下载工具把整个出口带宽吃满。OpenPortalServer的限速功能可以针对每个用户会话单独设置上行和下行速率。我当时给普通客人设置的是下行4Mbps、上行2Mbps足以应付刷视频和网页浏览又不会影响其他人。管理后台能实时看到在线用户列表包括IP地址、MAC地址、接入时长、已用流量对于异常占用资源的用户可以直接在后台踢下线。在线用户管控还需要设置两个超时参数会话空闲超时和总时长上限。空闲超时我设置的是30分钟超过30分钟没有流量动作会话自动回收避免大量僵尸会话挤占并发额度。总时长上限就是客人购买的券时长到点自动断线需要续费只能再购新码。4.4 认证门户页面定制要点门户页面是客人第一次接触到系统的界面直接影响到品牌形象和信任度。OpenPortalServer把页面模板放在了独立的模板目录里编辑起来比较友好。我在原有模板基础上改了三个地方把Logo和配色换成园区的VI样式在一级页面上加入服务条款的勾选项勾选后才能点连接按钮在认证成功页面上加了一段欢迎文案和WiFi使用规范。改模板时需要特别注意一点表单的提交地址和隐藏字段绝对不能动。这些字段承载着系统回传给网关的加密信息一旦被误删用户就算输入了正确的兑换码也过不了网关校验。我建议改模板前先用Git做一个版本标记万一改坏了可以快速回滚。5. 上线运营中的问题排查实录5.1 用户连上WiFi却跳不出认证页这个问题在测试阶段和上线初期出现频率最高。排查路径一般为先确认网关上的uamserver地址是否可达用一台连在用户网段的设备直接访问这个地址如果打不开就先查网段路由然后确认网关是否把HTTP流量拦截并重定向很多情况下是chilli服务没有正常启动重启一下即可最后检查用户的浏览器是否缓存了旧的页面状态换一个无痕窗口测试就能排除。还有一个容易被忽略的原因某些手机会强制走HTTPS连接比如iOS的智能热点登录检测它访问的是一个系统探测URL。如果网关没有配置针对这类探测流量的特殊处理用户就会卡在正在检测网络连接的状态。解决办法是在网关上把这类探测域名加入允许列表让它们无需认证即可访问或者直接放行系统的网络检测请求。5.2 认证成功但依然打不开网页这种症状通常意味着问题出在认证后的授权环节而不是认证本身。优先检查网关和Portal之间的共享密钥是否一致密钥不匹配时Portal认为已经通知网关放行了但网关校验回调签名失败拒绝放行。其次检查会话记账是否正常如果RADIUS记账请求超时网关可能一段时间后把已放行的会话强制断开。第三确认用户的IP在认证前后没有发生变化如果DHCP租期过短导致中途换IP认证会话会跟着失效。当时我处理过一个典型案例用户输完验证码页面显示连接成功但浏览器一直转圈打不开任何网站。排查下来是网关的MASQUERADE规则少了一条针对用户网段的条目导致用户流量出了内网之后再也没有回来。这类网络层的问题用tcpdump抓包看流向很快就能定位。5.3 兑换码泄漏与并发滥用的对策运营中最不想见到的情况就是兑换码被批量转卖或者超并发使用。单码并发限制可以在生成批次时设置但防不住有人用一个号的截图发给多个人。我后来做的补救措施是在后台定期筛查短期内登录次数异常的兑换码发现单个码在多个IP段反复登录就直接停用同时对短时券设置每日发放上限控制风险敞口。一旦发现大范围异常还可以在网关侧临时把认证模式切换成必须使用本地账号只对内部人员放行等兑换码批次清理完再恢复正常模式。5.4 时间不同步引发的玄学故障如果你发现用户会话时长忽长忽短、兑换码偶尔提前失效、RADIUS认证时通时不通先别急着怀疑代码检查一下所有服务器和网关的时间是否同步。NTP时间偏差一旦超过RADIUS协议的容忍范围就会产生各种难以解释的间歇性故障。我把Portal服务器、数据库、网关全部加入同一组NTP对时源终于在一次排查中发现数据库时间偏差已经达到好几十秒调整同步之后问题彻底消失。建议部署时就把NTP层级结构一次性搭好后面会省心很多。6. 写在最后这套老版本带给我的几点启发6.1 运维上的三点坚持用OpenPortalServer V3.3.5.6这套方案整整两年我的体会是开源项目只要找准定位稳定性和可用性完全不输商业产品关键在使用者愿不愿意花时间把基础配置做扎实。运维层面有几点想特别强调。第一数据库备份是生命线我用的是每天凌晨全量备份加binlog增量备份的策略有一次误操作删了三个月前的兑换码数据靠备份恢复了绝大部分损失被控制在可接受范围。第二升级要克制这个版本在现有场景里跑得好好的就没有必要因为新版本发布就立刻迁移新功能带来的收益如果小于迁移风险按兵不动就是最好的策略。第三所有登录和操作记录要保留足够长时间当出现兑换码纠纷或用户投诉时这些日志是定位问题的第一手依据。6.2 一个受用至今的回归测试习惯最后分享一个小技巧每次调整门户页面或认证参数之前先在测试环境用脚本模拟一次完整的认证流程把兑换码生成、提交认证、回调确认这几步跑通再推到生产环境。我写过一套基于curl的简易回归脚本每次改动后跑一遍基本能提前挡住九成以上的低级错误。这套流程后来被我用在了其他所有运维项目上算是这个老版本送给我的一项额外收获。如果你也在维护类似的认证门户系统真心建议把这个习惯建立起来它不会占用太多时间但在关键时刻真的能救命。本文还有配套的精品资源点击获取