💡 Tam çalışan örnek GitHub’da mevcuttur:
qr-sign-password-protected-pdf-python
Giriş
Bir belge imzalanması gerektiğinde şifreli çıktığı durumlarda çoğu ekip üç adımlı bir desen kullanır: belgeyi çöz, düz metin üzerinde imzala, sonucu tekrar şifrele. Bu yöntem çalışır. Ancak bu, birkaç yüz milisaniye boyunca kasıtlı olarak korunan bir belgenin okunabilir bir kopyasının geçici bir dizinde var olduğu anlamına gelir ve denetlenen bir işlem hattında bu pencere bulgu olur, imza değil.
Şifreli bir PDF’i imzalamak, .NET üzerinden Python için GroupDocs.Signature yeteneğidir ve bu üç adımı tamamen atlar: şifre, kaynağı yerinde açar, imza uygulanır ve çıktı yine şifreli olarak geri yazılır. Bu makale, iki çalışan ve iki kasıtlı başarısız yol olmak üzere dört şifre yolunu karşılaştırır ve bu bağlama özgü hata sözleşmesini açıklar.
Bunun Önemi Nedir?
Şifre yönetimi, belge işlem hatlarının sızdırıldığı yerdir. Genellikle imzalama kütüphanesinden değil, onun etrafındaki iskeletten kaynaklanır: silinmesi gereken geçici dosya, yanlış şifre hatasını yutan ve sonsuza kadar yeniden deneyen istisna işleyicisi, alıcıya hiç bildirilmemiş bir şifreyle verilen imzalı kopya.
Üçünün de aynı temel nedeni vardır: şifre, işlemin bir parçası olarak değil, sadece yol açmak için bir şey olarak ele alınır. LoadOptions ve SaveOptions şifreyi tekrar işleme dahil eder.
Önkoşullar
Python 3 ve groupdocs-signature-net==26.1, ayrıca bir kullanıcı şifresi olan PDF. Lisans olmadan kütüphane değerlendirme modunda çalışır; bu mod hâlâ imzalar ancak sayfaya kendi metnini ekler.
Kurulum
pip install groupdocs-signature-net==26.1
Yöntem 1 – Orijinal Şifreyi Koru
Varsayılan ve en az kod gerektiren yöntem. Şifre LoadOptions aracılığıyla girilir ve hiç SaveOptions geçirilmez:
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)
SaveOptions yokluğu burada gerçek işi yapar. use_original_password varsayılan olarak True olduğundan GroupDocs, imzalı çıktıya kaynak şifresini yeniden uygular. Diskte ya da başka bir yerde korumasız bir sürümün var olduğu bir an yoktur ve len(result.succeeded) kaç imzanın yazıldığını raporlar.
Yöntem 2 – İmzalı Kopyayı Yeniden Şifrele
İmzalı belge başka bir tarafa gönderildiğinde mantıklı hareket, kopyaya kendi kimlik bilgilerini vermek ve kaynağı olduğu gibi bırakmaktır:
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)
Her iki SaveOptions satırı da gereklidir ve hatırlanması gereken detay şudur: password ayarlanırken use_original_password varsayılanında bırakılırsa gözle görülür bir etkisi olmaz. Bayrak kazanır, çıktı eski şifreyi korur ve alıcı gönderdiğiniz şifrenin çalışmadığını bildirdiğinde bunu fark edersiniz.
Yöntem 3 ve 4 – İki Başarısızlık
Şifreli bir belge, eksik bir şifre ile yanlış bir şifreye farklı tepkiler verir ve bu farkın ele alınması gerekir.
Hiç LoadOptions kullanılmazsa, açma başarısız olur ve hiçbir şey yazılmaz:
try:
with signature.Signature(source_path) as sign:
sign.sign(output_path, options)
return ""
except RuntimeError as error:
return proxy_error_name(error)
Bu, PasswordRequiredException döndürür. Bunun yerine hatalı bir şifre sağlarsanız aynı kod IncorrectPasswordException döndürür. Biri kullanıcıdan kimlik bilgisi istemek anlamına gelir; diğeri ise elinizdeki kimlik bilgisinin artık geçerli olmadığını gösterir. İkisini ayırt edemeyen bir işleyici, asla çalışmayacak bir şifreyi yeniden denemeye devam eder.
Hata Sözleşmesi ve Neden Bariz Kod Kırılır
Kimse sizi uyarmazsa bir öğleden sonrayı tüketen kısım budur. Bağlama PasswordRequiredException, IncorrectPasswordException ve GroupDocsSignatureException isimlerini, BaseException‘dan türemeyen çıplak adlar olarak ortaya koyar. Sezgisel işleyiciyi yazın:
except IncorrectPasswordException:
...
ve Python şu hatayı verir: TypeError: catching classes that do not inherit from BaseException is not allowed. Orijinal hata kaybolur, yerine except satırınıza işaret eden bir hata gelir, şifreye değil. İlk kez tam olarak bu işleyiciyi yazdım ve TypeError’ı okumak için harcadığım yirmi dakika bu bölümün var olma nedenidir.
Aslında gelen şey, mesajı Proxy error(<Name>): ile başlayan bir RuntimeError. Bu önekin ayrıştırılması nedeni ortaya çıkar:
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]
Dönülen adı, dosya yolları ve çalıştırma sırasında değişebilen mesaj metni yerine, mesajın kendisinden ayırın.
İmzalamadan Önce İnceleme
Bilmeniz gereken beşinci bir yol daha vardır ve bu yol hiçbir şey yazmaz. Belgeyi LoadOptions ile açıp get_document_info çağırmak, formatı, sayfa sayısını ve boyutu döndürürken dosya hâlâ diskte şifreli kalır:
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
İki kullanım senaryosu vardır. Şifre bir kullanıcı formundan geliyorsa, bu kimlik bilgisini ucuz bir çağrıyla doğrular; iki yüz belge üzerinden bir toplu işlem sırasında değil. Ve bir işlem hattının hiçbir zaman düz metin depolamasına izin verilmediği durumlarda, yine de o hattın ne tuttuğunu raporlamasını sağlar – denetim günlüğü için sayfa sayıları, kota için boyutlar – hiçbir şeyi çözmeden.
Yöntemlerin Karşılaştırılması: Hangi Durumda Hangi Yöntem Kullanılır
| Yöntem | En Uygun Kullanım | Temel Avantajlar | Kısıtlamalar |
|---|---|---|---|
| Orijinal şifreyi koru | yerinde imzalayan işlem hatları | SaveOptions gerekmez, açıkta bir şey yazılmaz |
alıcı kaynak şifreyi bilmek zorunda |
| Kaydetme sırasında yeniden şifrele | başka bir tarafa devretme | kaynak kimliğini korur, kopya yeni bir şifre alır | iki SaveOptions satırı gerekir, sadece birini ayarlamak kolayca unutulabilir |
| Şifre yok (başarısız) | testlerde sözleşmeyi kanıtlama | açma sırasında başarır, hiçbir şey yazmaz | imzalama yolu değildir |
| Yanlış şifre (başarısız) | eski kimliği ayırt etme | farklı istisna adı | imzalama yolu değildir |
Tekrar Okuma Çağrısı Ekstra Maliyeti Haklı mı?
Evet, iki nedenden dolayı. QrCodeVerifyOptions ile imzalı dosyayı yeniden açmak, imzanın kaydetme sırasında hayatta kaldığını kanıtlar ve yeniden açma şifre talep ettiğinden çıktının hâlâ şifreli olduğunu da gösterir. Sıfır sayım neredeyse her zaman bir lisans sorunudur, imzalama hatası değil – imza çağrısı gerçekten başarısız olduğunda bir istisna fırlatır, bu yüzden sessizlik + sıfır, lisanssız bir derlemeye işaret eder.
Geçişin Maliyeti
Yapısal bir değişiklik yoktur. Kodunuz zaten bir geçici dosyaya çözümleme yapıyorsa, değişiklik bu adımı silmek, şifreyi LoadOptions içine taşımak ve sonunda yeniden şifreleme çağrısını kaldırmaktır – genellikle satır sayısında net bir azalma. İmza çağrısı kendisi şekil değiştirmez ve çıktı, girildiği sıradaki aynı korumaya sahip, bayt‑bayt aynı imzalı PDF olur.
Dikkat edilmesi gereken tek yer temizlik kodudur. Şifre‑çöz‑imza‑yeniden‑şifre et etrafında inşa edilmiş bir işlem hattı genellikle geçici dosyayı silen bir finally bloğuna sahiptir ve geçici dosya silindikten sonra bu blok artık var olmayan bir yolu silmeye çalışır.
En İyi Uygulamalar
use_original_passwordı yalnızca kasıtlı olarak döndürme (rotate) yapıyorsanız değiştirin; varsayılan güvenli olandır.- Proxy adını bir yardımcı işlevde bir kez ayrıştırın ve diğer yerlerde ona göre dallanma yapın.
- Bir toplu işlem başlatmadan önce kullanıcı tarafından sağlanan şifreyi
get_document_infoile doğrulayın; böylece hatalı bir kimlik bilgisi ucuz bir çağrı maliyetiyle ortaya çıkar, yarı‑tamamlanmış bir çalışmayı etkilemez. - İmzalı çıktıyı kaynak yolun üzerine asla yazmayın; böylece bir hata orijinali kurtarılabilir durumda bırakır.
Sonuç
Şifre, imzalamadan önce aşılması gereken bir engel değildir – işlemin bir argümanıdır. LoadOptions ile açın, SaveOptions ile çıktı korumasını belirleyin, bir şey başarısız olduğunda proxy adını ayrıştırın ve ardından şifreyle doğrulayın. Örnek, dört yolu bir kerede çalıştırır, böylece aralarındaki fark tek bir komutla görülür, bir paragrafla güvenilmez.