签到接口返回403主因是未通过登录态校验;需先调用登录接口获取JSESSIONID或token,再携带Cookie或Authorization头请求,且注意User-Agent、Referer、时间戳等校验项。

签到接口找不到或返回403,先确认是否绕过了登录态校验
绝大多数OA系统(如泛微e-cology、致远A8、蓝凌MK)的签到接口不是公开的,必须携带有效的会话凭证。直接请求 /api/attendance/checkin 或类似路径,90% 情况下会返回 403 Forbidden 或跳转到登录页。
真实流程是:先用账号密码 POST 到登录接口(如 /login 或 /j_spring_security_check),拿到 Set-Cookie 中的 JSESSIONID 或 token,再在后续请求头中带上 Cookie 或 Authorization。漏掉这步,脚本永远“没登录”。
- 用浏览器开发者工具(Network → Preserve log)完整录一次手动签到过程,重点看登录成功后的第一个重定向响应头和所有后续请求的
Cookie/headers - 别依赖
requests.Session()自动管理 cookie 就万事大吉——有些OA会校验 User-Agent、Referer 甚至请求时间戳,缺一不可 - 如果登录接口返回的是加密响应(比如字段全为
data+sign),说明启用了前端签名,Python 直接模拟几乎不可行,得考虑 PyExecJS 或调用已有的 JS 签名逻辑
POST 签到请求发出去但无效果,检查 body 和 timestamp 校验
签到不是发个空 POST 就完事。常见限制包括:timestamp 必须是当前毫秒级时间(且服务器会校验±30秒内)、sign 是对参数+密钥的 MD5 或 SHA256、location 字段需为有效 GPS 坐标或内网 IP 对应的地理围栏编码。
例如泛微某版本要求 body 为 JSON:
{"userId":"123","time":1717028345123,"sign":"a1b2c3...","lat":"31.2304","lng":"121.4737"}其中 sign = md5(userId + time + "your_secret_key")。少拼一个字段,服务端就静默丢弃请求。
立即学习“Python免费学习笔记(深入)”;
- 抓包对比手动签到与脚本请求的完整 body,逐字段比对,特别注意数字类型(
123vs"123")、空格、换行 - 服务器时间可能与本地不同,优先用 OA 接口(如
/api/system/time)获取服务器时间戳,而非int(time.time() * 1000) - 部分系统要求
Content-Type: application/x-www-form-urlencoded,但 body 实际是 JSON 字符串——这种反直觉设计很常见,务必按抓包结果来
定时执行时被识别为异常行为,加随机延迟和 UA 轮换
每天早上 9:00 整准时发起请求,连续一周,OA 的风控模块大概率会把该账号标记为“机器人”,轻则要求短信验证,重则冻结接口调用权限。
真实员工操作有偏差:有人 8:58 点,有人 9:03 才点,IP 可能从办公网切换到手机热点,User-Agent 也不总一样。脚本得模拟这种“不规律”。
- 设置触发时间窗口(如 8:55–9:05),用
random.randint(8*60+55, 9*60+5)生成分钟级偏移,再加秒级随机(+ random.randint(0, 59)) - 准备 3–5 个真实 UA 字符串(Chrome、Edge、Firefox 最新版本),每次请求随机选一个,写进
headers - 关键:避免使用
time.sleep()硬等——改用系统级定时(Linuxcron或 Windows 任务计划程序)触发脚本,脚本自身只做单次签到逻辑
如何安全存储账号密码而不硬编码在脚本里
把 username = "zhangsan" 和 password = "123456" 写死在 Python 文件里,等于把门禁卡贴在公司玻璃门上。
最简可行方案是读取环境变量:os.getenv("OA_USER"),然后在运行前执行 export OA_USER="zhangsan"。更稳妥的做法是用 keyring 库存入系统凭据库:
import keyring
keyring.set_password("oa_system", "zhangsan", "real_password_here")后续脚本中直接 keyring.get_password("oa_system", "zhangsan") 获取,密码由操作系统加密保护,不会出现在进程列表或日志中。
- 绝对不要用 base64 或简单异或“加密”密码——那只是混淆,毫无安全性可言
- 如果公司用统一身份认证(如 LDAP/OAuth2),优先走 SSO 登录流程,获取临时 token,比维护账号密码更可持续
- 定期检查 OA 是否更新了登录机制(比如加了滑块验证码),这类变更通常不会通知脚本维护者,得靠日志报警及时发现
实际跑起来后,最难缠的往往不是代码,而是 OA 后台悄悄升级了前端签名算法,或者安全策略突然收紧——这类变动不会报错,只会让签到成功率从 100% 慢慢掉到 0%,而且没有任何提示。


















