前言
故事时间:2020年下半年(具体时间忘记了😭)
当时刚刚下定决心要转专业,所以有好多新奇的想法不断涌现。就比如做一个一键请假的脚本,但是那就必须想办法登录上学校的e站通(一个教职工以及学生的办事平台)才能实现各种各样的想法。
所以最初的Python版本就开始提上日程了。后来,发现了一款鸿蒙的课程表APP做的很棒,但是没有适配我们学校,于是我又写了Java版。再后来,学了Flutter,要做一款疫情填报APP,于是写了Dart版。
准备
我们学校的网站是用的cas统一身份认证。
打开开发者工具后,在 网络
选项中勾选 保留日志
(如果不保留日志,页面跳转后会清空日志信息)。
输入账号密码后直接点击登陆。
点击登录后就到了最重要的一步,找到提交身份认证信息的请求。很明显,这个 login
请求就是我们要找的请求。
点开请求后找到负载,也就是我们提交的表单。发现里面并没有我们刚刚提交的密码,但是有一条是 rsa
,这说明我们的密码是在前端加密后发送至服务器的。
于是我打开了 源代码
选项卡,找到了登陆函数。从这里可以发现, ul
是账号的长度、 pl
是密码的长度、 lt
是id为 lt
的标签值、 rsa
是用 strEnc
函数加密后的返回值,登陆函数最后提交了表单。
我们现在需要找的就是lt标签值和 strEnc
函数。我们先找 lt
标签。
不出所料,果然在页面中发现了隐藏的信息。表单提交的所有内容都被隐藏放在了页面的最后。
然后在 des.js
文件中找到了加密函数 strEnc
。
现在所有内容都已经准备好了,根据我的分析,身份验证的表单内容应该是:
rsa: 加密算法通过账号密码以及lt字符串拼接加密后的一串字符串
ul: 账号长度
pl: 密码长度
lt: 登陆标识,每次刷新页面都会更新
execution: 登陆失败次数记录(因为会随我登陆失败次数增加而增加)
_eventId: 固定值submit
Python版
用到的库有 bs4 | requests | execjs
,其中 execjs
是用来调用js文件的,用来实现加密算法(重新用Python写一遍实在是太麻烦了)。
根据前面准备内容的思路来写代码,首先是要建立一个会话,访问登陆页面去获取各项信息(lt、execution、_eventId)。
session = requests.Session()
login_url = "http://cas.upc.edu.cn/cas/login"
response = session.get(url=login_url)
soup = BS(response.content,'lxml')
LT = re.findall('value="(.*?)"/',str(soup.find_all('input',id="lt")[0]))[0]
execution = re.findall('value="(.*?)"/',str(soup.find_all('input',attrs={'name': "execution"})[0]))[0]
_eventId = re.findall('value="(.*?)"/',str(soup.find_all('input',attrs={'name': "_eventId"})[0]))[0]
然后根据获取的信息以及账号密码,调用 des.js
文件中 strEnc
函数来加密。
des = execjs.compile(open("./des.js").read())
rsa = des.call("strEnc",user+password+LT,"1","2","3")
建立表单,发送请求。
data = {
"rsa": rsa,
"ul": len(user), "pl": len(password),
"lt": LT, "execution": execution, "_eventId": _eventId
}
response = session.post(url=login_url,data=data,verify=False)
全部代码
import requests
import execjs
from bs4 import BeautifulSoup as BS
import re
requests.packages.urllib3.disable_warnings()
def login(user, password):
session = requests.Session()
login_url = "http://cas.upc.edu.cn/cas/login"
response = session.get(url=login_url)
soup = BS(response.content,'lxml')
LT = re.findall('value="(.*?)"/',str(soup.find_all('input',id="lt")[0]))[0]
execution = re.findall('value="(.*?)"/',str(soup.find_all('input',attrs={'name': "execution"})[0]))[0]
_eventId = re.findall('value="(.*?)"/',str(soup.find_all('input',attrs={'name': "_eventId"})[0]))[0]
des = execjs.compile(open("./des.js").read())
rsa = des.call("strEnc",user+password+LT,"1","2","3")
data = {
"rsa": rsa,
"ul": len(user),
"pl": len(password),
"lt": LT,
"execution": execution,
"_eventId": _eventId
}
response = session.post(url=login_url,data=data,verify=False)
if response.status_code == 200 :
print("登陆成功")
return session
else: print("登陆失败")
其他版本
写了,但是有点久远了~