本文档只说明校园网登录与注销本身的 HTTP 落地逻辑,不讨论本项目的界面、托盘、更新、函数名或模块拆分。
1. 总体思路
这套校园网认证不是“直接提交账号密码然后等结果”这么简单,而是通常分成三步:
- 先请求状态接口,确认当前是否已经在线
- 如果在线,判断是不是当前账号在线,还是别的账号在线
- 再决定执行登录,还是先注销再登录,或者直接返回“无需重复登录”
当前落地里,状态检测、登录、注销这三类请求都使用 GET。
2. 三类接口的默认地址
默认会使用两组地址:
- 状态检测接口:
http://10.2.5.251/drcom/chkstatus - 登录/注销接口:
http://10.2.5.251:801/eportal/
也就是说,默认约定是:
chkstatus走 80 端口eportal认证走 801 端口
如果学校环境修改了网关地址,本质上也还是这两类接口:
- 一个用于查在线状态
- 一个用于提交登录/注销动作
3. 为什么先查状态接口
状态接口不是辅助信息,而是整条认证链路的基础。
先查状态的原因有三个:
- 判断当前网络是不是已经认证成功
- 判断当前在线的是不是目标账号
- 取出后续登录/注销要用的
wlan_user_ip
也就是说,登录和注销都依赖状态接口返回的 IP 信息,而不是随便取本机网卡 IP。
4. 状态检测接口的请求方式
状态检测走 GET。
请求形式大致是:
GET http://10.2.5.251/drcom/chkstatus?callback=dr{timestamp}&v={random}
关键点:
callback=dr{timestamp}:这是一个 JSONP 回调名v={random}:通常是一个随机数,用来尽量避免缓存
这里不是普通纯 JSON 接口,而是 JSONP 风格返回。
5. 状态检测接口的返回解析
返回内容通常长这样:
dr1743926400000({"result":1,"uid":"20230001@cmcc","v46ip":"10.x.x.x"})
解析逻辑很直接:
- 找到第一个
( - 找到最后一个
) - 取出中间的 JSON 字符串
- 再按 JSON 反序列化
解析后最关键的字段是:
result1表示在线- 非
1一般表示未认证
uid- 当前在线账号
v46ipv4ipss5
IP 的提取顺序通常是:
v46ip -> v4ip -> ss5
谁先有值就用谁。
这个 IP 后面会继续用于:
- 登录请求里的
wlan_user_ip - 注销请求里的
wlan_user_ip
6. 登录接口的请求方式
请求结构大致如下:
GET http://10.2.5.251:801/eportal/?c=Portal&a=login
&callback=dr{timestamp}
&login_method=1
&user_account={account}
&user_password={password}
&wlan_user_ip={ip}
&wlan_user_mac=000000000000
&wlan_ac_ip=
&wlan_ac_name=
&jsVersion=3.0
&_={timestamp}
其中最关键的参数是:
c=Portala=loginlogin_method=1user_accountuser_passwordwlan_user_ip
7. 登录参数怎么拼
7.1 user_account
账号一般不是裸学号,而是:
学号@运营商
例如:
20230001@cmcc
20230001@unicom
20230001@telecom
如果是纯校园网、不带运营商后缀,则直接传学号本身。
7.2 user_password
密码放在查询参数里,因此必须做 URL 编码。
否则一旦密码里有这些字符,就会把整个查询串打坏:
&+%=
所以正确做法不是“把密码原样拼上去”,而是先编码,再放进 URL。
7.3 wlan_user_ip
这个字段不建议自己猜,也不建议直接读本机网卡地址。
更稳妥的做法是:
- 先从
chkstatus返回里取 - 优先取
v46ip - 再回退
v4ip - 再回退
ss5
因为校园网认证系统认的,往往是它自己状态接口里看到的在线 IP。
7.4 其他参数
callback=dr{timestamp}:用于 JSONP 风格返回_={timestamp}:常见防缓存参数wlan_user_mac=000000000000:当前实现里固定值wlan_ac_ip=、wlan_ac_name=:当前留空jsVersion=3.0:按现网接口习惯保留
8. 登录前的实际判断逻辑
真正落地时,登录前一般先按下面顺序判断:
- 调状态接口
- 如果已经在线:
- 如果在线账号就是目标账号,直接返回“已在线”
- 如果在线账号是别的账号,先提示“是否顶号”
- 如果未在线:
- 直接发登录请求
这意味着“顶号判断”本质上不是登录接口单独返回的概念,而是靠状态接口先发现“已有别的账号在线”。
9. 强制登录时为什么要先注销
如果确认要顶号,更稳妥的做法不是直接再次登录,而是:
- 先发注销请求
- 等注销成功
- 再发登录请求
这样能把“别的账号已在线”的状态先清掉,减少新登录被网关拒绝或状态异常的概率。
10. 注销接口的请求方式
当前校园网注销同样走 GET。
请求结构大致如下:
GET http://10.2.5.251:801/eportal/?c=Portal&a=logout
&callback=dr{timestamp}
&login_method=1
&user_account=drcom
&user_password=123
&ac_logout=0
&wlan_user_ip={ip}
&wlan_user_ipv6=
&wlan_vlan_id=1
&wlan_user_mac=000000000000
&wlan_ac_ip=
&wlan_ac_name=
&jsVersion=3.0
&_={timestamp}
这里最关键的是:
a=logoutwlan_user_ip
以及这组相对固定的参数:
user_account=drcomuser_password=123ac_logout=0wlan_vlan_id=1
这说明注销接口不是“把登录时那套账号密码重新传一遍”,而是按网关要求提交一组固定格式参数。
11. 登录/注销的成功判定
返回文本不一定总是统一格式,所以实际落地里更常见的是“启发式判定成功”。
一个常见做法是只要命中以下任一特征,就认为成功:
"result":"1""result":1成功success
优点:
- 对不同学校或不同版本网关的兼容性更强
缺点:
- 不是严格协议校验
- 如果网关返回格式变化很大,可能需要再补新的成功特征
12. 为什么这里没有 POST
就这套现网协议来说,当前落地使用的是:
- 状态检测:
GET - 登录:
GET - 注销:
GET
不是:
- 状态检测
GET,登录POST - 或登录/注销都
POST
所以如果后续要迁移到别的学校环境,首先要确认的不是账号格式,而是:
- 它的登录接口到底是
GET还是POST - 参数是在 query string 里,还是 form body 里
- 注销是不是也复用同一套入口
13. 异常处理的落地思路
协议层通常要区分两种失败:
13.1 请求根本没打通
这类问题包括:
- 不在校园网环境
- 校园网网关地址不通
- 系统代理把请求带偏了
- TUN 模式接管了流量
- 超时
这种情况本质上不是“账号密码错”,而是“没有成功直连认证网关”。
13.2 请求打通了,但业务失败
这类问题包括:
- 账号错误
- 密码错误
- 网关返回未成功状态
- 当前已有别的账号在线
这两类问题要分开处理,否则用户会把“网络不通”误以为“密码错了”。
14. 一条完整的落地链路
如果把校园网认证逻辑抽象成协议层,完整流程可以概括成:
GET /drcom/chkstatus- 解析 JSONP
- 取出:
- 是否在线
- 当前在线账号
wlan_user_ip
- 如果已经是目标账号在线,直接结束
- 如果是别的账号在线,先询问是否顶号
- 若确认顶号,先
GET /eportal/?c=Portal&a=logout... - 再
GET /eportal/?c=Portal&a=login... - 根据返回文本判断成功或失败
这就是当前校园网登录/注销最核心的协议落地逻辑。