2023-Python内外外网登录新版正方教务系统实现课表查询等功能

1、前言

哈喽哈喽,今天是星期6!!!愉快的一周~
最近有想写个对接学校教务系统的微信小程序,但是我搞不到现成的接口,去抓包学校官方的小程序,又没抓到,那就只有去看学校的教务系统网站了。
学校用的是正方教务系统 如下图:
正方教务系统
值得说明的是:我们学校是分内网外网访问教务系统的。内网登录要有专门的账号才能连接, 其在小程序中对于用户是不便的,所以决定用Python实现外网登录正方教务系统。(能外网登录的前提就是实现了内网的登录)

2、webvpn 页面分析和登录实战效果

百度百科:WebVPN提供基于web的内网应用访问控制,允许授权用户访问只对内网开放的web应用,实现类似VPN(虚拟专用网)的功能。
外网登录:学校webvpn登录

http://ids.cqyti.com/authserver/login?service=http%3A%2F%2Fwebvpn.cqyti.com%3A8333%2Fusers%2Fauth%2Fcas%2Fcallback%3Furl#

下面是认证首页:
在这里插入图片描述
登录查看其参数:

需要关注的参数:验证码先不管。

  • username: 学号
  • password: 加密后的密码
  • execution: 请求的网页中

execution:√

在这里插入图片描述
password:√
这个密码大概找了一下,后面遇到了一个接口,它密码是没加密的,我就没有用上面这个接口了。
首先我们看这个密码:

VDHBe29XwDbfdppkXA54Y3uHvq+9WIE3TsaButGDYRv8IZ60UNO97TMtzEHP6HB5eqp3V4sEe59oRFE9h9wgQUty6PdqTcn0Qxpb7hp77LM=

初看,没看出来是什么东西 (博主是新手,见谅~) ,这样就只有一步一步地去找js。
先全局搜几个关键词试试:发现没什么作用
在这里插入图片描述
不慌,全局没找到,就去一个一个看js。
在这里插入图片描述
英文好的朋友,就会发现:encrypt 就是加密的意思,那我首先进入查看它:
在这里插入图片描述
emm~ 看到这里密码加密就差不多就找到了, 断点看看:右键Open in Sou..
在这里插入图片描述
选取合适的地方
加密
进行调试分析:
网页的 js :

function getAesString(data, key0, iv0) {
    
    
    key0 = key0.replace(/(^\s+)|(\s+$)/g, "");
    var key = CryptoJS.enc.Utf8.parse(key0);
    var iv = CryptoJS.enc.Utf8.parse(iv0);
    var encrypted = CryptoJS.AES.encrypt(data, key, {
    
    
        iv: iv,  // 偏移量
        mode: CryptoJS.mode.CBC,  // CBC 加密方式
        padding: CryptoJS.pad.Pkcs7  // Pkcs7 填充方式
    });
    return encrypted.toString();
}


function encryptAES(data, aesKey) {
    
    
    if (!aesKey) {
    
    
        return data;
    }
    var encrypted = getAesString(randomString(64) + data, aesKey, randomString(16));
    return encrypted;
}


function encryptPassword(pwd0, key) {
    
    
    try {
    
    
        return encryptAES(pwd0, key);
    } catch (e) {
    
    }
    return pwd0;
}
var $aes_chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
var aes_chars_len = $aes_chars.length;



function randomString(len) {
    
    
    var retStr = '';
    for (i = 0; i < len; i++) {
    
    
        retStr += $aes_chars.charAt(Math.floor(Math.random() * aes_chars_len));
    }
    return retStr;
}

仔细看:
主要js 就是 randomString()getAesString()
在这里插入图片描述
python中代码实现上述加密:

""""
CSDN:抄代码抄错的小牛马
"""
#  pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host pypi.tuna.tsinghua.edu.cn  pycryptodome==3.9.0
# pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host pypi.tuna.tsinghua.edu.cn PyExecJS
#  from Crypto.Cipher import AES 安装成功后还报错,解决--> 先确定安装成功,再找到 crypto 的安装文件夹 ,将其改为:Crypto  大写的 C
from Crypto.Cipher import AES
import random
import base64

aes_chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'  # 48
aes_chars_len = len(aes_chars)


# 产生随机字符
def randomString(len1):
    retStr = ''
    for i in range(len1):
        retStr += aes_chars[random.randint(0, aes_chars_len - 1)]
    return retStr
    pass


# 加密
def getAesString(data, key0, iv0):
    data = pad(data)

    key = key0.encode('utf-8')
    mode = AES.MODE_CBC
    iv = iv0

    print('key1', key)
    print('mode', mode)
    print('i_v', iv.encode("utf-8"))
    print('============================')

    print(len(data))
    # 创建加密对
    AES_obj = AES.new(key, mode, iv.encode("utf-8"))
    # 完成加密
    AES_en_str = AES_obj.encrypt(data.encode("utf-8"))
    # 用base64编码一下
    AES_en_str = base64.b64encode(AES_en_str)
    # 最后将密文转化成字符串
    AES_en_str = AES_en_str.decode("utf-8")

    return AES_en_str

    pass


# 补位  必须为 16 的倍数
def pad(data):
    length = 16
    count = len(data)
    if count < length:
        add = (length - count)
        data = data + ('\0' * add)
    elif count > length:
        add = (length - (count % length))
        data = data + ('\0' * add)

    return data


if __name__ == '__main__':
    username = '111111111'  # 学号
    data = '123456'  # 密码
    key0 = randomString(16)
    iv0 = randomString(16)
    key = key0
    iv = iv0
    enctext = getAesString(data, key, iv)
    print(enctext)
    enctext2 = getAesString(enctext, key, iv)
    print(enctext2)
    print()
    end_pass = randomString(64) + enctext2  # 最终加密的密码
    print('最终的:', end_pass)
    print('最终的长度:', len(end_pass))

    pass

查看:
在这里插入图片描述
在线检验: 在线加密解密工具
在这里插入图片描述
再:
在这里插入图片描述
最后的密码就是: 随机 64 为字符 + 上面的
好! 这个接口就这样了。当时我在调试上面的接口时,找到了一个新的接口,它密码不加密就可以登录…
如下:
在这里插入图片描述
都是一个用户认证,进入到同一个页面。
authenticity_token 在页面页可以直接找到:
在这里插入图片描述
代码登录:

""""
CSDN:抄代码抄错的小牛马
"""
# 获取公钥
# http://192-168-200-87.webvpn.cqyti.com:8333/jwglxt/xtgl/login_getPublicKey.html?time=1680257350906&_=1680257350774
# 登录接口
# http://192-168-200-87.webvpn.cqyti.com:8333/jwglxt/xtgl/login_slogin.html?time=1680257303310
# ----------------------------------------------------------------------------------------------------------------------
# 获取公钥
import requests
import time
import re
import binascii
import rsa

url1 = 'http://webvpn.cqyti.com:8333/login'  # get 获取 authenticity_token
url2 = 'http://webvpn.cqyti.com:8333/users/sign_in'  # Post 登录到 教务系统 和学工系统选择页面
url3 = f'http://192-168-200-87.webvpn.cqyti.com:8333/jwglxt/xtgl/login_getPublicKey.html?time={
      
      str(int(time.time() * 1000))}'
url4 = f'http://192-168-200-87.webvpn.cqyti.com:8333/jwglxt/xtgl/login_slogin.html?time={
      
      str(int(time.time() * 1000))}'

print(url3)
print(url4)

# 外网进入教务系统的校验  学号+身份证后六位
username = '111111'
password1 = '123456'
password2 = '1234567890'

# 获取当前13位时间戳
t = str(int(time.time() * 1000))

# 创建session会话
session = requests.session()
# 设置请求头 url1 的请求头
session.headers.update({
    
    
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
    'Accept-Encoding': 'gzip, deflate',
    'Accept-Language': 'zh-CN,zh;q=0.9',
    'Cache-Control': 'max-age=0',
    'Connection': 'keep-alive',

    'Host': 'webvpn.cqyti.com:8333',
    'If-None-Match': 'W/"f6d3997ea652f3611badf669a518a1f6"',
    'Referer': 'http://webvpn.cqyti.com:8333/login',
    'Upgrade-Insecure-Requests': '1',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36',
})

# 获取 authenticity_token  http://webvpn.cqyti.com:8333/login
loginPage = session.get(url1)
loginPage.encoding = 'utf-8'
authenticity_token = re.search('name="authenticity_token" value="(.*?)"', loginPage.text).group(1)

# print(authenticity_token)

# 登录信息   Post 登录到 教务系统 和学工系统选择页面
Login_Data = {
    
    
    'utf8': '✓',
    'authenticity_token': authenticity_token,
    'user[check_path]': 'login',
    'user[otp_with_capcha]': 'false',
    'user[double_factor]': 'false',
    'user[login]': username,
    'user[password]': password1,
    'user[dymatice_code]': 'unknown',
    'commit': '登录 Login',
}

res = session.post(url=url2, data=Login_Data)  # Post 登录到 教务系统 和学工系统选择页面

print(res.status_code)
print('------------------------------------------------------------------------')
cookie_dict = requests.utils.dict_from_cookiejar(session.cookies)
cookie = res.cookies

print(session.cookies)
print()

结果:
在这里插入图片描述
好了,到这里我们是可以直接去登录教务系统了:
参数:
在这里插入图片描述
csrftoken:
在这里插入图片描述
验证码没做处理,那就只剩密码了:分析
在这里插入图片描述
在这里插入图片描述
可见:
在这里插入图片描述
OK 了~~
python 代码实现:

""""
CSDN:抄代码抄错的小牛马
"""
import requests
import time
import re
import binascii
import rsa

# 获取当前13位时间戳
t = str(int(time.time() * 1000))
url1 = 'http://webvpn.cqyti.com:8333/login'  # get 获取 authenticity_token
url2 = 'http://webvpn.cqyti.com:8333/users/sign_in'  # Post 登录到 教务系统和学工系统 选择页面

# 外网进入教务系统的校验: 默认情况下--> 学号+身份证后六位  webvpn
username = '111111111'
password1 = '123456'
password2 = '1234567890'


#  webvpn
def webvpn():
    # 创建session会话
    session = requests.session()
    # 设置请求头 url1 的请求头
    session.headers.update({
    
    
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
        'Accept-Encoding': 'gzip, deflate',
        'Accept-Language': 'zh-CN,zh;q=0.9',
        'Cache-Control': 'max-age=0',
        'Connection': 'keep-alive',
        'Host': 'webvpn.cqyti.com:8333',
        'If-None-Match': 'W/"f6d3997ea652f3611badf669a518a1f6"',
        'Referer': 'http://webvpn.cqyti.com:8333/login',
        'Upgrade-Insecure-Requests': '1',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36',
    })
    # 获取 authenticity_token  http://webvpn.cqyti.com:8333/login
    loginPage = session.get(url1)
    loginPage.encoding = 'utf-8'
    authenticity_token = re.search('name="authenticity_token" value="(.*?)"', loginPage.text).group(1)
    # print(authenticity_token)
    # 登录信息   Post 登录到 教务系统 和学工系统 选择页面
    Login_Data = {
    
    
        'utf8': '✓',
        'authenticity_token': authenticity_token,
        'user[check_path]': 'login',
        'user[otp_with_capcha]': 'false',
        'user[double_factor]': 'false',
        'user[login]': username,
        'user[password]': password1,
        'user[dymatice_code]': 'unknown',
        'commit': '登录 Login',
    }

    res = session.post(url=url2, data=Login_Data)  # 发起Post 登录到 教务系统 和学工系统选择页面
    # obj = re.compile(r'<li class="col-md-3 col-sm-6 col-xs-12">.*?<a href="(?P<href>.*?)"', re.S)
    # result = obj.finditer(res.text)
    # lists = []
    # for item in result:
    #     # href = item.group('href')
    #     # 0 教务系统 1 学工系统
    #     lists.append(item.group('href'))
    # print(lists)
    print(res.status_code)
    print('------------------------------------------------------------------------')
    # 查看 cookie
    cookie_dict = requests.utils.dict_from_cookiejar(session.cookies)
    cookie = res.cookies

    # print(session.cookies)
    print(cookie)
    # print(cookie_dict)
    print()
    return cookie


# 密码 --> 加密 rsa
def get_password(pw, modulus):
    weibo_rsa_e = 65537
    message = str(pw).encode()
    rsa_n = binascii.b2a_hex(binascii.a2b_base64(modulus))
    key = rsa.PublicKey(int(rsa_n, 16), weibo_rsa_e)
    encropy_pwd = rsa.encrypt(message, key)
    the_enpassword = binascii.b2a_base64(encropy_pwd)
    return the_enpassword


#  正方教务系统登录页面
def zfjwxt(cookie):
    session = requests.session()
    # xx = session.get(lists[0],cookies=cookie)
    xx = session.get(url='http://192-168-200-87.webvpn.cqyti.com:8333/jwglxt/xtgl/login_getPublicKey.html?time=' + t,
                     cookies=cookie)
    publicKey = xx.json()
    print(publicKey)

    # 对密码进行加密
    enPassword = get_password(password2, publicKey['modulus'])

    # 获取 csrftoken  http://192-168-200-87.webvpn.cqyti.com:8333/jwglxt/xtgl/login_slogin.html?time=1680257303310
    csrftoken_url = 'http://192-168-200-87.webvpn.cqyti.com:8333/jwglxt/xtgl/login_slogin.html?time=' + t
    login_zf = session.get(csrftoken_url)
    login_zf.encoding = 'utf-8'
    # csrftoken = re.search('name="csrftoken" value="(.*?)"', login_zf.text).group(1)
    csrftoken = re.search('name="csrftoken" value="(.*?)"', login_zf.text).group(1)

    # print(login_zf)
    print('------------------- csrftoken -------------------')
    print(csrftoken)
    print()

    # 登录信息 正方教务系统登录 页面
    info = {
    
    
        'csrftoken': csrftoken,
        'language': 'zh_CN',
        'yhm': username,
        'mm': enPassword,
        'mm': enPassword
    }

    # post 提交 学号+密码 登录
    res = session.post('http://192-168-200-87.webvpn.cqyti.com:8333/jwglxt/xtgl/login_slogin.html?time=' + t, info)
    cookie2 = res.cookies
    print(cookie2)
    print("------------------- 登录中 -------------------")
    if re.findall('用户名或密码不正确', res.text):
        print('用户名或密码错误.....')
        print()
    else:
        print("登陆成功")
        print()
        # 查询课表 其他改下参数即可
        kebiao(session)
        # 关闭会话
        session.close()


# 查询 课表
def kebiao(session):
    # session = requests.session()
    # 查询 课表
    # http://192-168-200-87.webvpn.cqyti.com:8333/jwglxt/kbcx/xskbcx_cxXsgrkb.html?gnmkdm=N2151&su=2020214371
    data = {
    
    
        'xnm': 2022,
        'xqm': 12,
        'kzlx': 'ck',
        'xsdm': '',
    }
    # cookies=cookie2
    kebiao = session.post(
        'http://192-168-200-87.webvpn.cqyti.com:8333/jwglxt/kbcx/xskbcx_cxXsgrkb.html?gnmkdm=N2151&su=' + username,
        data=data,
    )
    kb = kebiao.json()
    print(kb)


def main():
    print('程序结束...')


if __name__ == '__main__':
    cookie = webvpn()
    cookie2 = zfjwxt(cookie)
    main()

效果:
效果
这样就可登录进去了,这里简单的进行了课表的查询,如要进行其他信息的获取,直接session请求对应接口即可。
拜~~~ 我们下次再见 ^ _ ^

猜你喜欢

转载自blog.csdn.net/qq_61122628/article/details/129890735