发布于 

如何在手机上设置南大 APP 自动打卡(二)

我之前对于网络登录请求是没有太多了解的,只是知道需要发送含有账号和密码的表单。但是通过写这个登录脚本,我对于 CAS 登录方式有了大致的认识,至少可以成功登录南大的统一身份认证。

在实现的过程中,我参考了不少实现 CAS 登录的教程,其中大部分是登录大学网站的。在这里,我来简述一下我对于实现流程的理解。

登录

首先,观察登录过程中涉及到的各种请求,发现首先向统一身份认证的服务器发送了含有账号密码的表单。但是观察表单,其中密码显然是经过加密的,而且表单中还含有其他内容。

审查登录界面的 HTML 代码,可以找到一个 id 名为 casLoginForm 的表单,这里面就是我们需要提交的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<form id="casLoginForm" class="fm-v clearfix amp-login-form" role="form"
action="/authserver/login?service=http%3A%2F%2Fehallapp.nju.edu.cn%2Fxgfw%2Fsys%2Fyqfxmrjkdkappnju%2Fapply%2FgetApplyInfoList.do"
method="post">
<p>
<i class="auth_icon auth_icon_user"></i>
<input id="username" name="username" placeholder=" 账号 Username" class="auth_input" type="text" value="">
<span id="usernameError" style="display:none;" class="auth_error">Please input username</span>
</p>
<p>
<i class="auth_icon auth_icon_pwd"></i>
<input id="password" placeholder=" 密码 Password" class="auth_input" type="password" value="" autocomplete="off">
<input id="passwordEncrypt" name="password" style="display:none;" type="text" value="">
<span id="passwordError" style="display:none;" class="auth_error">Please input password</span>
</p>
<p id="cpatchaDiv">
</p>
<p>
<button type="submit" class="auth_login_btn primary full_width">Sign in
</button>
</p>
<div class="footer">
<a href="https://itsc.nju.edu.cn/tysfrz_21651/list.htm" target="_blank" class="n1">Help</a>
<a href="https://authserver.nju.edu.cn/authserver/getBackPasswordMainPage.do" class="n3">Forgot Password</a>
</div>
<div class="other_login_type" style="margin-top: 15px;display: none;">
<fieldset class="oth_type_tit">
<legend align="center" class="oth_type_txt">其他方式登录</legend>
</fieldset>
<div class="oth_type_links">
<a href="combinedLogin.do?type=weixin&amp;success=https://authserver.nju.edu.cn/authserver/login?service=http%3A%2F%2Fehallapp.nju.edu.cn%2Fxgfw%2Fsys%2Fyqfxmrjkdkappnju%2Fapply%2FgetApplyInfoList.do"
style="display: inline-block;" class="icon_type">
<img src="/authserver/custom/images/weixin.png" alt="logo">
</a>
</div>
</div>

<input type="hidden" name="lt" value="LT-xxxxxx-xxxxxx-xxxx-cas">
<input type="hidden" name="dllt" value="userNamePasswordLogin">
<input type="hidden" name="execution" value="e2s1">
<input type="hidden" name="_eventId" value="submit">
<input type="hidden" name="rmShown" value="1">
<input type="hidden" id="pwdDefaultEncryptSalt" value="xxxxxxxx">
</form>

可以看到,里面除了账号密码,还有很多 input 标签被设置为隐藏。这些隐藏的内容也是我们需要提交的。

在表单的最后,还有一个 idpwdDefaultEncryptSalt的标签,这是我们用来加密的密钥。

在了解我们需要提交的内容以后,就可以模拟登录了。

查看 js 文件,找到表单提交的代码,发现其中的密码被一个叫做 _etd2 的函数加密。函数有两个参数,第一个是密码,第二个是密钥。找到函数的定义部分,可以发现函数实际上使用了 AES 加密函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var casLoginForm = $("#casLoginForm");
casLoginForm.submit(doLogin);
function doLogin() {
var username = casLoginForm.find("#username");
var password = casLoginForm.find("#password");
var captchaResponse = casLoginForm.find("#captchaResponse");

if (!checkRequired(username, "usernameError")) {
username.focus();
return false;
}

if (!checkRequired(password, "passwordError")) {
password.focus();
return false;
}

if (!checkRequired(captchaResponse, "cpatchaError")) {
captchaResponse.focus();
return false;
}
_etd2(password.val(),casLoginForm.find("#pwdDefaultEncryptSalt").val());
}


function _etd2(_p0,_p1) {try{var _p2 = encryptAES(_p0,_p1);$("#casLoginForm").find("#passwordEncrypt").val(_p2);}catch(e){$("#casLoginForm").find("#passwordEncrypt").val(_p0);}}

在另一个 encrypt.js 文件中,可以找到 encryptAES 函数的实现部分,在实际的 python 代码中,通过 pyexecjs 来调用这个加密函数,不需要自己实现。

在 python 代码中,通过 get 方法得到表单中所需的各种信息,通过 post 方法向认证平台提交内容。这里 get 和 post 请求需要在同一个 session 中进行,表单中的 lt 和密钥都是动态的。

发送表单后,我们可以从 Response Headers 中得到我们需要的 Ticket,以 ST 开头。这里由于在之前添加了 service 的参数,所以页面会使用 ticket 参数重定向到我们指定的 service 页面,可以使用 allow_redirects=False 阻止重定向。

在打卡页面中,访问 Location 对应的网址,同样阻止重定向,可以在返回的 Cookie 中找到 MOD_AUTH_CAS 的值。

打卡

我们可以用获取到的值 MOD_AUTH_CAS 作为 cookie 来登录打卡信息页面,获取当日打卡的具体内容和唯一编号 wid。

之后使用同样的 MOD_AUTH_CAS 登录提交页面,通过 post 方式提交 wid 和健康状况就可以完成打卡。

部分参考

CAS 使用账号密码实现单点登陆

南科大 CAS 单点登录之模拟登录

抓取 2020 年最新版正方教务系统——在 Android 执行 JS 脚本实现 AES 加密

CAS 实现单点登录

CAS 自定义登录

Python 代码调用 JS 函数

Python 模拟登录华工新版教务系统选课

CAS Ticket 票据:TGT、ST、PGT、PT、PGTIOU

Python 中用 requests 处理 cookies 的 3 种方法

python requests 请求禁止跳转重定向