💡 Full working example available on GitHub: qr-sign-password-protected-pdf-python
Úvod
Existuje tříkrokový vzor, ke kterému se většina týmů uchyluje, když se ukáže, že dokument, který je potřeba podepsat, je zašifrovaný: dešifrujte jej, podepište prostý text a výsledek znovu zašifrujte. Funguje to. Znamená to také, že po několik stovek milisekund existuje čitelná kopie úmyslně chráněného dokumentu v dočasném adresáři a v auditovaném pipeline je právě toto okno zjištěním, nikoli podpisem.
Podepisování chráněného PDF je schopnost GroupDocs.Signature pro Python přes .NET, která tyto tři kroky úplně vynechává: heslo otevře zdroj na místě, podpis se aplikuje a výstup se zapíše zpět chráněný. Tento článek porovnává čtyři cesty s heslem – dvě fungující a dvě úmyslně selhávající – a popisuje smlouvu o selhání, která je specifická pro toto propojení.
Proč je to důležité
Zpracování hesel je místem, kde pipeline dokumentů uniká. Ne skrze samotnou knihovnu pro podepisování, obvykle, ale skrze obal kolem ní: dočasný soubor, který měl být smazán, obslužná rutina výjimek, která pohltila chybu špatného hesla a neustále znovu zkoušela, nebo podepsaná kopie předaná s heslem, o kterém příjemce nikdy neví.
Všechny tři situace mají stejný kořenový důvod – heslo je považováno za něco, co je potřeba odstranit, místo aby bylo součástí operace. LoadOptions a SaveOptions ho vrací zpět do operace.
Požadavky
Python 3 a groupdocs-signature-net==26.1, plus PDF s uživatelským heslem. Bez licence knihovna běží v evaluačním režimu, který stále podepisuje, ale přidá vlastní text na stránku.
Instalace
pip install groupdocs-signature-net==26.1
Metoda 1 – Zachovat původní heslo
Výchozí a zároveň ta, která vyžaduje nejméně kódu. Heslo se předává přes LoadOptions a SaveOptions se vůbec nepoužívá:
load_options = LoadOptions()
load_options.password = password
options = _build_qr_options(qr_text)
with signature.Signature(source_path, load_options) as sign:
result = sign.sign(output_path, options)
return len(result.succeeded)
Absence SaveOptions zde dělá skutečnou práci. use_original_password má výchozí hodnotu True, takže GroupDocs znovu použije původní heslo na podepsaný výstup. Neexistuje okamžik, kdy by nechráněná verze existovala na disku nebo jinde, a len(result.succeeded) udává, kolik podpisů bylo zapsáno.
Metoda 2 – Přenastavit heslo podepsané kopie
Když má podepsaný dokument jít k jiné straně, rozumným krokem je dát kopii vlastní přihlašovací údaje a nechat zdroj nedotčený:
save_options = SaveOptions()
save_options.password = new_password
save_options.use_original_password = False
with signature.Signature(source_path, load_options) as sign:
result = sign.sign(output_path, options, save_options)
return len(result.succeeded)
Obě řádky SaveOptions jsou povinné a právě to je detail, který stojí za zapamatování: nastavení password při zachování výchozí hodnoty use_original_password nic nepozorovatelného nezmění. Příznak přebíjí, výstup si ponechá staré heslo a vy to zjistíte, až když příjemce oznámí, že heslo, které jste poslali, nefunguje.
Metoda 3 a 4 – Dvě selhání
Zašifrovaný dokument reaguje odlišně na chybějící heslo a na špatné heslo, a tato rozdílnost stojí za ošetření.
Bez jakýchkoli LoadOptions se otevření nezdaří a nic se nezapíše:
try:
with signature.Signature(source_path) as sign:
sign.sign(output_path, options)
return ""
except RuntimeError as error:
return proxy_error_name(error)
Toto vrací PasswordRequiredException. Pokud místo toho poskytnete nesprávné heslo, stejný kód vrátí IncorrectPasswordException. Jedno znamená požádat uživatele o přihlašovací údaje; druhé znamená, že máte zastaralé údaje. Obsluha, která je nedokáže rozlišit, bude znovu zkoušet heslo, které nikdy nefunguje.
Smlouva o selhání a proč zjevný kód selhává
Zde je část, která stojí odpoledne, pokud vás nikdo nevaruje. Propojení vystavuje PasswordRequiredException, IncorrectPasswordException a GroupDocsSignatureException jako holé názvy, které nezdědí z BaseException. Napíšete intuitivní obsluhu:
except IncorrectPasswordException:
...
a Python vyhodí TypeError: catching classes that do not inherit from BaseException is not allowed. Původní chyba zmizí a je nahrazena chybou, která ukazuje na váš řádek except místo na heslo. Právě tuto obsluhu jsem napsal poprvé a dvacet minut strávených čtením TypeError je důvod, proč tato sekce existuje.
Co skutečně přichází, je RuntimeError, jehož zpráva začíná Proxy error(<Name>): . Parsování tohoto prefixu obnoví příčinu:
message = str(error)
marker = "Proxy error("
if not message.startswith(marker):
return ""
start = len(marker)
end = message.find(")", start)
if end < 0:
return ""
return message[start:end]
Rozvětvěte podle vráceného jména místo podle textu zprávy, který obsahuje cesty k souborům a liší se mezi běhy.
Kontrola před podpisem
Existuje pátá cesta, kterou je dobré znát, a která vůbec nic nezapisuje. Otevření dokumentu s LoadOptions a volání
get_document_info vrátí formát, počet stránek a velikost, zatímco soubor zůstane na disku zašifrovaný:
with signature.Signature(source_path, load_options) as sign:
info = sign.get_document_info()
return info.file_type.file_format, info.page_count, info.size
Dva využití. Když heslo přišlo z uživatelského formuláře, tato metoda ověří přihlašovací údaje levnou voláním místo toho, aby se provádělo uprostřed dávky dvou set dokumentů. A když pipeline nesmí vůbec ukládat prostý text, stále umožňuje pipeline hlásit, co drží – počet stránek pro auditní log, velikosti pro kvótu – aniž by něco dešifrovala.
Porovnání metod: Kdy použít kterou
| Metoda | Nejvhodnější pro | Klíčové výhody | Omezení |
|---|---|---|---|
| Zachovat původní heslo | pipeline, které podepisují na místě | žádné SaveOptions, nic se neukládá v otevřené podobě |
příjemce potřebuje původní heslo |
| Přenastavit heslo při uložení | předání jiné straně | zdroj si ponechá své heslo, kopie získá nové | dva řádky SaveOptions, snadno se nastaví jen jeden |
| Žádné heslo (selhání) | dokazování smlouvy v testech | selže při otevření, nic se nezapíše | není to cesta pro podepisování |
| Špatné heslo (selhání) | rozlišení zastaralých údajů | odlišný název výjimky | není to cesta pro podepisování |
Stojí se zpětné načtení za další volání?
Ano, ze dvou důvodů. Opětovné otevření podepsaného souboru s QrCodeVerifyOptions dokazuje, že podpis přežil uložení, a protože při opětovném otevření musíte zadat heslo, také dokazuje, že výstup je stále zašifrovaný. Nulový počet téměř vždy signalizuje problém s licencí, nikoli selhání podpisu – volání sign vyvolá výjimku při skutečném selhání, takže ticho plus nula odpovídajících ukazuje na nelicencovanou verzi.
Co to stojí přepnout
Nic strukturovaného. Pokud váš kód už dešifruje do dočasného souboru, změna spočívá v odstranění tohoto kroku, přesunutí hesla do LoadOptions a vynechání volání re-encrypt na konci – typicky čistý úbytek řádků. Samotné volání podpisu se nemění, a výstup je bajt po bajtu podepsané PDF se stejnou ochranou, jakou mělo při vstupu.
Jediné místo, kde je třeba být opatrný, je úklidový kód. Pipeline postavená kolem dešifruj-podepiš-rešifruj obvykle má blok finally, který maže dočasný soubor, a jakmile je dočasný soubor smazán, tento blok se snaží smazat cestu, která už neexistuje.
Nejlepší postupy
- Nenechávejte
use_original_passwordna změněném hodnotě, pokud neprovádíte záměrnou rotaci; výchozí nastavení je bezpečné. - Parsujte název proxy jednou v pomocné funkci a všude jinde na něj branchujte.
- Ověřte uživatelem zadané heslo pomocí
get_document_infopřed zahájením dávky, aby špatný údaj stál jen jedno levné volání místo polovičně dokončeného běhu. - Nikdy nepřepisujte podepsaný výstup přes cestu ke zdroji, aby chyba nevedla ke ztrátě originálu.
Závěr
Heslo není překážkou, kterou je třeba obejít před podpisem – je argumentem operace. Otevřete s LoadOptions, rozhodněte o ochraně výstupu pomocí SaveOptions, parsujte název proxy při selhání a následně ověřte pomocí hesla. Ukázka spouští všechny čtyři cesty najednou, takže rozdíl mezi nimi vidíte jedním příkazem místo odstavce důvěry.