【置顶】疫情期间自动健康打卡暨CAS单点登录认证实践

  • 2020-03-10
  • 3,864
  • 3
  • 0

[2020.3.11 update]

插播广告:各位找工作/找实习的小伙伴,可以内推商汤科技(SenseTime)各种岗位(开发、CV研究员、项目管理、产品经理 and so on~),欢迎踊跃提交简历~

p.s. 我作为一个后端程序员,写的前端代码(emmm,网页post,get这些就算是前端吧)确实很菜很辣鸡,请见谅🤪


代码实现了统一身份认证系统的CAS SSO登录,以及健康打卡表单自动填写,然后邮件发送打卡结果

邮件那个sendmail.py我就不发出来了,网上一搜一大把,我也是网上搜的orz

耗时一整天,终于把它写完了!

初次学习使用CAS认证,目前的代码只保证了功能可用,但还有很多不足。例如,没有有效利用session与cookie,只能每次登录重新获取。

注:自动打卡的前提是你有一台服务器或者24小时开机的电脑,设置定时执行脚本(Linux crontab)


Python代码

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-

"""
实现疫情期间每天自动打卡

Created on 2020-03-10 23:10
@author: Zhang Jiawei
"""

import requests
import lxml.html
import re
import json
import random
import time
import traceback
headers = {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
    "Accept-Encoding": "gzip, deflate, br",
    "Accept-Language": "zh-CN",
    "Cache-Control": "max-age=0",
    "Connection": "keep-alive",
    "Content-Type": "application/x-www-form-urlencoded",
    "Cookie": "MESSAGE_TICKET=%7B%22times%22%3A0%7D; ",
    "Host": "cas.hrbeu.edu.cn",
    "Referer": "https://cas.hrbeu.edu.cn/cas/login?service=http%3A%2F%2Fjkgc.hrbeu.edu.cn%2Finfoplus%2Flogin%3FretUrl%3Dhttp%253A%252F%252Fjkgc.hrbeu.edu.cn%252Finfoplus%252Fform%252FJSXNYQSBtest%252Fstart",
    "Upgrade-Insecure-Requests": "1",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18362"
}

data = {
    "username":"******",    ## 用户名
    "password":"******"     ## 密码
}
def findStr(source, target):
    return source.find(target) != -1
title = ""
msg = ""

try:
    #get
    url_login = 'https://cas.hrbeu.edu.cn/cas/login?service=http%3A%2F%2Fjkgc.hrbeu.edu.cn%2Finfoplus%2Fform%2FJSXNYQSBtest%2Fstart'
    # print ("begin to login ..")
    sesh = requests.session()
    req = sesh.get(url_login)
    html_content = req.text

    #post
    login_html = lxml.html.fromstring(html_content)
    hidden_inputs=login_html.xpath(r'//div[@id="main"]//input[@type="hidden"]')
    user_form = {x.attrib["name"] : x.attrib["value"] for x in hidden_inputs}

    user_form["username"]=data['username'];
    user_form["password"]=data['password'];
    user_form["captcha"]='';
    user_form["submit"]='登 录';
    headers['Cookie'] = headers['Cookie'] + req.headers['Set-cookie']

    req.url = f'https://cas.hrbeu.edu.cn/cas/login;jsessionid={req.cookies.get("JSESSIONID")}?service=http%3A%2F%2Fjkgc.hrbeu.edu.cn%2Finfoplus%2Fform%2FJSXNYQSBtest%2Fstart'
    response302 = sesh.post(req.url, data=user_form, headers=headers)
    casRes = response302.history[0]
    # print("*******************    ", findStr(casRes.headers['Set-Cookie'],'CASTGC'))

    #get
    jkgc_response = sesh.get(response302.url)

    #post
    headers['Accept'] = '*/*'
    headers['Cookie'] = jkgc_response.request.headers['Cookie']
    headers['Host'] = 'jkgc.hrbeu.edu.cn'
    headers['Referer'] = jkgc_response.url
    jkgc_html = lxml.html.fromstring(jkgc_response.text)
    csrfToken = jkgc_html.xpath(r'//meta[@itemscope="csrfToken"]')
    csrfToken = csrfToken.pop().attrib["content"]
    jkgc_form = {
        'idc': 'JSXNYQSBtest',
        'release': '',
        'csrfToken': csrfToken,
        'formData': {
            '_VAR_URL': jkgc_response.url,
            '_VAR_URL_Attr': {
                'ticket': re.match(r'.*ticket=(.*)', jkgc_response.url).group(1)
            }
        }
    }
    jkgc_form['formData'] = json.dumps(jkgc_form['formData'])
    jkgc_url = 'http://jkgc.hrbeu.edu.cn/infoplus/interface/start'
    response3 = sesh.post(jkgc_url, data=jkgc_form, headers=headers)

    #get
    form_url = json.loads(response3.text)['entities'][0]
    form_response = sesh.get(form_url)

    #post
    headers['Accept'] = 'application/json, text/javascript, */*; q=0.01'
    headers['Referer'] = form_url
    headers['X-Requested-With'] = 'XMLHttpRequest'
    submit_url = 'http://jkgc.hrbeu.edu.cn/infoplus/interface/doAction'

    submit_html = lxml.html.fromstring(form_response.text)
    csrfToken2 = submit_html.xpath(r'//meta[@itemscope="csrfToken"]')
    csrfToken2 = csrfToken2.pop().attrib["content"]

    submit_form = {
        'actionId': '1',
        'boundFields': 'fieldCXXXdqszdjtx,fieldCXXXjtgjbc,fieldGLJL,fieldMQJCRxh,fieldCXXXsftjhb,......',   ## 表单数据需要自己先手动执行一遍然后粘贴过来
        'csrfToken': csrfToken2,
        'formData': r'{"fieldCXXXsftjhbs":"","fieldCXXXsftjhb":"2",......',                                 ## 表单数据需要自己先手动执行一遍然后粘贴过来
        'lang': 'zh',
        'nextUsers': '{}',
        'rand': str(random.random() * 999),
        'remark': '',
        'stepId': re.match(r'.*form/(\d*?)/',form_response.url).group(1),
        'timestamp': str(int(time.time()+0.5))
    }
    response_end = sesh.post(submit_url, data=submit_form, headers=headers)

    ## 表单填写完成,返回结果
    print('表单地址: ', form_response.url)
    print('表单状态: ', response_end.text)
    title = f'打卡成功<{submit_form["stepId"]}>'
    msg = '表单地址: ' + form_response.url + '\n\n表单状态: ' + response_end.text
except:
    err = traceback.format_exc()
    print('报错信息: \n', err)
    title = '打卡失败!!!'
    msg = '报错信息: \n' + err
finally:
    ## 发送邮件
    import sendmail     ## 这个是普通.py文件,不是Python库
    sendmail.sendmail(title, msg)

 


参考资料

  1. PYTHON 实现CAS服务器认证:https://blog.csdn.net/seu_04004414/article/details/81661668 or http://www.freesion.com/article/225192597/
  2. CAS单点登录原理(包含详细流程,讲得很透彻,耐心看下去一定能看明白!):https://blog.csdn.net/ban_tang/article/details/80015946
  3. 利用Python requests库实现cas认证:https://www.cnblogs.com/cherryjing/p/9626277.html

评论

  • 初夏阳光回复

    虽然不大懂 py 但是调试完了能用,学长代码真香 2333

    好像是辣个认证开了代理的话就不好使。Traceback 会报 http.client.RemoteDisconnected urllib3.exceptions.MaxRetryError requests.exceptions.ProxyError 这样的。

    (顺便请问我可以把调试完的代码发到我的博客吗?

    • zjw1111回复

      可以转发。你说的代理指的是什么代理?

      • 初夏阳光回复

        我用的是 Clash 那个,设置是按规则代理非全局,报错显示请求好像是走我的 127.0.0.1:7890 出去的。

发表评论

冀ICP备19026961号