import zipfile, os, shutil WAR = "docker/cas.war" CLS_DIR = "target/cas/WEB-INF/classes/org/apereo/cas/web/custom/controller" SRC_INDEX = "src/main/webapp/front/index.html" IDX_ENTRY = "front/index.html" files = { os.path.join(CLS_DIR, "LoginController.class"): "WEB-INF/classes/org/apereo/cas/web/custom/controller/LoginController.class", os.path.join(CLS_DIR, "LoginController$LocalAuthenticationResult.class"): "WEB-INF/classes/org/apereo/cas/web/custom/controller/LoginController$LocalAuthenticationResult.class", SRC_INDEX: IDX_ENTRY, "src/main/resources/application.yml": "WEB-INF/classes/application.yml", } tmp = WAR + ".tmp" zin = zipfile.ZipFile(WAR) zout = zipfile.ZipFile(tmp, "w", zipfile.ZIP_DEFLATED) for item in zin.infolist(): if item.filename in files.values(): continue zout.writestr(item, zin.read(item.filename)) zin.close() for src, entry in files.items(): data = open(src, "rb").read() # 用原条目元数据保持权限/时间戳 zi = zipfile.ZipInfo(entry) zi.date_time = (2026, 8, 3, 18, 10, 0) zi.compress_type = zipfile.ZIP_DEFLATED zi.external_attr = 0o644 << 16 zout.writestr(zi, data) zout.close() os.replace(tmp, WAR) # 校验 z = zipfile.ZipFile(WAR) print("testzip:", z.testzip()) idx = z.read(IDX_ENTRY).decode("utf-8", "replace") cls = z.read("WEB-INF/classes/org/apereo/cas/web/custom/controller/LoginController.class").decode("latin1") yml = z.read("WEB-INF/classes/application.yml").decode("utf-8", "replace") print("index.html has ?v=1.8:", "?v=1.8" in idx) print("index.html has real form action /api/login:", 'action="/api/login"' in idx) print("index.html has loginname hidden:", 'name="loginname"' in idx) print("class has window.location.href (v1.8 success):", "window.location.href" in cls) print("class has guard /cas/login fallback:", 'contains("/cas/login")' in cls) yml_ok = "default-redirect-url: /front/index.html" in yml and "default-redirect-url: /cas/login" not in yml print("application.yml default-redirect-url fixed (/front/index.html):", yml_ok) print("WAR size:", os.path.getsize(WAR))