校园网账号的登录/登出操作在本质上是本机向校内的认证服务器发送了一个含有校园网账号和密码、DHCP 服务器为本机分配的内网 IP,本机的 MAC 地址等信息的网络请求。想要在无图形界面的服务器上实现校园网账号的登录/登出首先需要获取校园网认证服务的 API 接口地址和参数列表。

首先使用浏览器(这里使用网络工具更好用的 Firefox)打开校园网登录界面,F12 打开开发者工具,找到网络一栏。

image-20220308140022455.png

开发者工具的网络一栏可以实时拦截并解析网页中发送和接收的网络请求,此时输入账号密码并点击登录后即可获得所有相关的网络请求链接。

image-20220308140349679.png

可以通过过滤 URL 的方式寻找和登录(login)有关的关键字来查找相关网络请求,可以看到这里第一个请求就是校园网账号登录操作的 URL 链接。

浏览器的开发者工具一般都会为每个请求链接提供 cURL 命令格式的复制选项,根据服务器所在的平台不同,复制相应的 cURL 命令即可。由于服务器运行的是 Linux,这里采用 POSIX 标准的命令进行复制。

image-20220308140628335.png

复制得到的命令中的一些琐碎的参数可以去除,留下关键的参数即可。

原始命令

curl 'https://w.seu.edu.cn:801/eportal/?c=Portal&a=login&callback=dr1003&login_method=1&user_account=校园网账号&user_password=校园网密码&wlan_user_ip=DHCP服务器为本机分配的内网IP&wlan_user_ipv6=&wlan_user_mac=000000000000&wlan_ac_ip=&wlan_ac_name=&jsVersion=3.3.2&v=4680' -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0' -H 'Accept: */*' -H 'Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2' -H 'Accept-Encoding: gzip, deflate, br' -H 'Connection: keep-alive' -H 'Referer: https://w.seu.edu.cn/' -H 'Cookie: PHPSESSID=iallep4oe53qg6uc5osr6ir99e' -H 'Sec-Fetch-Dest: script' -H 'Sec-Fetch-Mode: no-cors' -H 'Sec-Fetch-Site: same-site'

精简后的命令

curl 'https://w.seu.edu.cn:801/eportal/?c=Portal&a=login&callback=dr1003&login_method=1&user_account=校园网账号&user_password=校园网密码&wlan_user_ip=DHCP服务器为本机分配的内网IP&wlan_user_ipv6=&wlan_user_mac=000000000000&wlan_ac_ip=&wlan_ac_name=&jsVersion=3.3.2&v=4680'

根据网络请求参数可知,登录所需的数据主要为校园网账号和密码、本机的内网 IP 地址。

接下来只需要按照参数要求编写脚本即可,这里由于是给实验室的服务器使用,且服务器是通过有线网络连接的校园网,因此在获取内网 IP 前需要知道有线网络接口的设备号:

❯ ifconfig
enp0s31f6: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        ether d8:5e:d3:00:cd:9d  txqueuelen 1000  (以太网)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
        device interrupt 16  memory 0x92f00000-92f20000

enp4s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.201.171.20  netmask 255.255.0.0  broadcast 10.201.255.255
        inet6 fe80::b2bc:727b:e991:6108  prefixlen 64  scopeid 0x20<link>
        inet6 2001:da8:1002:6001::1:c472  prefixlen 128  scopeid 0x0<global>
        ether d8:5e:d3:00:cd:9e  txqueuelen 1000  (以太网)
        RX packets 15824654  bytes 17179835542 (17.1 GB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 12938830  bytes 3148614000 (3.1 GB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
        device memory 0x92b00000-92bfffff

可以看到 enp4s0 这个网口设备连接的是校园网,获取 enp4s0 的 MAC 地址:

❯ cat /sys/class/net/enp4s0/address
d8:5e:d3:00:cd:9e

获取相应的内网 IP 地址:

❯ ifconfig enp4s0 | grep inet | grep -v inet6 | sed 's/^[ \t]*//g' | cut -d ' ' -f 2 | awk '{print $1}'
10.201.171.20

至此已经获取了登录所需的全部数据,编写相应的登录脚本即可:

login.sh

#!/bin/bash
eth="enp4s0"
ip=$(ifconfig enp4s0 | grep inet | grep -v inet6 | sed 's/^[ \t]*//g' | cut -d ' ' -f 2 | awk '{print $1}')
mac=$(cat /sys/class/net/${eth}/address)

echo eth: ${eth}
echo mac: ${mac}
echo ip: ${ip}

echo '---------Login---------'
echo ""
read -p "username : " user_account  
read -sp "password : " user_password

request="https://w.seu.edu.cn:801/eportal/?c=Portal&a=login&callback=dr1003&login_method=1&user_account=${user_account}&user_password=${user_password}&wlan_user_ip=${ip}&wlan_user_ipv6=&wlan_user_mac=000000000000&wlan_ac_ip=&wlan_ac_name=&jsVersion=3.3.2&v=2820"
curl ${request}

最后通过 chmod 命令为脚本文件添加可执行权限即可。

校园网账号的登出的实现与上述过程类似,即先获取登出操作的网络请求链接,根据链接解析所需的参数,编写脚本获取相应的参数并通过 cURL 向校园网服务器提交登出请求即可。

logout.sh

#!/bin/bash
eth="enp4s0"
ip=$(ifconfig enp4s0 | grep inet | grep -v inet6 | sed 's/^[ \t]*//g' | cut -d ' ' -f 2 | awk '{print $1}')
mac=$(cat /sys/class/net/${eth}/address)

echo eth: ${eth}
echo mac: ${mac}
echo ip: ${ip}
mac_full=(${mac//:/})

echo '---------Logout---------'
read -p "username : " user_account

request="https://w.seu.edu.cn:801/eportal/?c=Portal&a=logout&callback=dr1004&login_method=1&user_account=drcom&user_password=123&ac_logout=1&register_mode=1&wlan_user_ip=${ip}&wlan_user_ipv6=&wlan_vlan_id=1&wlan_user_mac=${mac_full}&wlan_ac_ip=&wlan_ac_name=&jsVersion=3.3.2&v=2785"
curl ${request}