Siber Güvenlik

Hibernate Envers ile Veri Denetimi

Günümüzde verinin çok önemli olması nedeniyle, uygulamalardaki veri değişikliklerini takip etmek oldukça tercih edilen bir gereksinim haline geldi. Bu amaca ulaşmak için çeşitli seçenekler bulunuyor ve “Hibernate Envers” da bu çözümlerden biridir.

Necmeddin Tapan |

01.12.2023

Hibernate Envers nedir?

 

Hibernate Envers, entity’lerin versiyonlanmasını sağlayan bir projedir. Peki Hibernate Envers ne işe yarar? Hibernate Envers ile, “Entity”lerinizdeki tüm değişiklikleri kaydetmek ve denetlemek kolaydır. Bir varlığın tüm değişiklikleri ile geçmişi, denetim tablolarında bulunabilir. Ayrıca "kimin değişiklik yaptığı" gibi bazı ekstra bilgiler de denetim tablolarına eklenebilir.

 

Temel Kullanım

 

Projenizde Hibernate Envers kullanmak için, aşağıdaki bağımlılığı “pom.xml” dosyanıza eklemeniz yeterli olur:

 

Hibernate Envers dependency

 

Bir sonraki adım, denetlemek istediğiniz Entity class’ınıza @Audited anotasyonunu eklemektir. Bu anotasyon ile Hibernate-Envers, ekleme, güncelleme ve silme işlemlerinden kaynaklanan tüm değişiklikleri denetleyecektir. @Audited anotasyonu hem Entity için (tüm tablo için) hem de Kolonlar için (belirli bir alan için) eklenebilir.

 

Hibernate Envers Audited Anotasyon

 

@AuditTable, veri tabanındaki denetim tablosunun adını tanımlayan isteğe bağlı bir anotasyondur. Varsayılan durumda, Hibernate-Envers “tabloAdi_AUD” adıyla denetim tablosu oluşturur. Denetim tabloları için ek (tüm denetim tabloları) ve diğer yapılandırmalar uygulama özellikleri (properties) dosyasında değiştirilebilir.

 

Denetlenen bir varlığın bir alanı denetlemesi istenmediği durumda, @NotAudited anotasyonu kullanılmalıdır. Örnek olarak, şifre değişiklikleri denetim için önemli değildir. @NotAudited anotasyonu ile “password” alanındaki değişiklikler Hibernate-Envers tarafından yok sayılacaktır.

 

Hibernate Envers Not Audited Anotasyon

 

Not; “User” entity için " issues" ilişkisi de @NotAudited olarak işaretlenmiştir. Eğer bu ilişkinin denetlenmesi isteniyorsa, “Issue” entity classı da @Audited anotasyonu ile denetlenmelidir.

 

Şimdi, veri tabanında denetim tablolarını oluşturabiliriz. Hibernate yapılandırmasında "ddl-auto: update" kullanıyorsanız, tablolar otomatik olarak oluşturulacaktır.

 

ddl-auto: update

 

Tabloları manuel olarak oluşturmak istiyorsanız, ilk oluşturulması gereken tablo "REVINFO" olmalıdır. Bu tablo, denetlenen tablolar için “primary key” olarak "rev" kolonunu tutar ve "revtstmp" kolonunu da değişiklik zamanını olarak belirtir.

 

Revinfo tablosu

 

Tüm varlıklarınız için denetim tabloları (eğer @Audited ise, örneğin "USERS_AUDIT") oluşturulmalıdır. “entity_audit” tablolarını oluştururken, denetlenen alanların farkında olmalı ve @NotAudited alanlarını eklememelisiniz. "rev" ve "revtype" alanları denetlenen tablolara eklenmelidir. Denetim tablosundaki "revtype", değişiklik tipi için kullanılır (0-> ekleme, 1->güncelleme, 2->silme).

 

Not; "rev" kolonunun artırılması için veri tabanında "sequence" (sıra) da oluşturulmalıdır.

 

Bu konfigürasyonlar ile Hibernate-Envers çalışmaya hazırdır. Başarılı bir yapılandırmadan sonra, veri tabanında aşağıdaki tabloları göreceksiniz.

 

Hibernate users audit tablosu

 

Yukarıda görüldüğü gibi, USERS_AUDIT tablosunda tüm denetlenen alanlar (“password” hariç), ayrıca "rev" ve "revtype" alanları bulunmaktadır. Bundan böyle, “Users” objelerinde (USERS tablosundaki) tüm değişiklikler bu tabloda tutulacaktır.

 

Not; “Users” objesini değiştirmek için “native query” kullanırsanız, bu Hibernate-Envers tarafından yakalanamaz, bu nedenle bu tür değişiklikler denetlenemez.

 

Yeni Alanlarla Gelişmiş Kullanım

 

İlk kısım, Hibernate-Envers'ın temel kullanımıdır, bu bölümde yeni özellikler eklenecektir. Revizyon tablosu, denetlenen varlıkta herhangi bir değişiklik yapan kullanıcının "kullanıcı adı" veya "IP adresi" gibi yeni bilgilerle genişletilebilir.

 

Yeni alanlar eklemek için, “DefaultRevisionEntity”i implement eden özel bir “RevisionEntity” sınıfı yazılmalıdır. Yeni sınıf, denetlenen varlığı değiştiren "modifierUser" (değiştirici kullanıcı) gibi değişiklikler hakkında tutmak istediğiniz alanları içermelidir.

 

Hibernate Envers ile Veri Denetimi

 

Not; MyRevisionEntity veri tabanında farklı bir tablo olarak oluşturulacaktır. Eğer MyRevisionEntity'den önce "revinfo" ve "audit" tabloları varsa, bu hataya neden olabilir. Bunu önlemek için, revinfo ve audit tablolarını silmeniz veya MyRevisionEntity tablo adını "revinfo" olarak değiştirmeniz gerekebilir.

 

MyRevisionEntity sınıfında görüldüğü gibi, @RevisionEntity anotasyonu özel bir RevisionListener sınıfı gerektirir. Bu, RevisionListener'ı implement etmeli ve "newVersion" metodunu override etmelidir. Bu method, RevisionEntity'de yeni eklenen alanı (modifierUser) yakalayacak şekilde yazılmalıdır.

 

Hibernate envers RevisionListener

 

"@Audited" anotasyonuna "withModifiedFlag = true" özelliği eklenebilir. Bu, hangi alanların değiştiğini bulmada yardımcı olur. Bu seçenek, denetim kayıtları için sorgular yazdığımızda daha net hale gelecektir.

 

Hibernate Envers Auditing

 

Değişikliklerden sonra, son tablolar aşağıdaki gibi olmalıdır. Görüldüğü gibi, "revinfo" yerine "MY_REVISION_ENTITY" tablosu var ve "MODIFIER_USER" adında ekstra bir kolon var. Ayrıca, USERS_AUDIT tablosunda "_MOD" son eki olan yeni alanlar var. Bu, "withModifiedFlag = true" seçeneğiyle ilgilidir ve o kolonun değişip değişmediğini gösterir.

 

Hibernate users audit son tablosu

 

Denetim Kayıtlarında Sorgulama

 

Önceki bölümlerde, Hibernate-Envers varlıkla ilgili tüm değişiklikleri yakalar ve denetim günlükleri oluşturur demiştik. Bu denetim günlükleri arasında arama yapmak için AuditReader interface’i kullanılmalıdır. AuditReaderFactory aracılığıyla EntityManager veya Session'dan elde edilebilir.

 

Hibernate envers audit reader factory

 

İlk örnek sorgu, ".eq" filtresiyle belirli bir kullanıcının tüm geçmişini (revizyonlarını) almak için kullanılır. Filtrelenen özellik (bu örnekte = "id"), Entity sınıfındaki denetlenen alanlardan biri olmalıdır. "forRevisionsOfEntity(User.class, true, true)" ifadesindeki User.class, hangi varlığın kayıtlarının alınacağını tanımlar. Diğer parametreler "selectEntitiesOnly" ve "selectDeletedEntities"dir.

 

Hibernate envers sorgulama

 

İlk örnekte "selectEntitiesOnly=true" seçilmiştir ve sonuç olarak, dönen sonuç listesi tipi User.class'tır. Peki, belirli bir kullanıcının revizyon bilgileriyle tüm geçmişini almak istesek ne olur? Bunun için "selectEntitiesOnly=false" kullanılmalıdır. Aşağıda görüldüğü gibi, dönen sonuç listesi tipi üç nesne dizisine değişmiştir:

 

  • İlki değiştirilen varlıktır.
  • İkincisi, "kim değiştirdi", "ne zaman değişti" ve "rev" bilgilerini tutan MyRevisionEntity'dir. Eğer özel RevisionEntity sınıfı kullanılmamışsa, dönüş tipi DefaultRevisionEntity olmalıdır.
  • Üçüncüsü, işlem tipinin bir numaralandırması olan RevisionType'tır: ADD (ekleme), MOD (güncelleme), DEL (silme).

 

Hibernate Envers revision type

 

Yalnızca "email" alanı değişmiş kullanıcıların geçmişini almak için, sorguya ".hasChanged()" uygulanmalıdır. Bu sorguyu kullanabilmek için, @Audited anotasyonuna "withModifiedFlag=true" eklenmelidir. Daha spesifik sorgular yapmak için hem ".eq" hem de ".hasChanged()" aynı anda kullanılabilir.

 

Hibernate Envers email değişikliği

 

Implement edilmiş RevisionEntity'e eklenen "modifierUser" alanını kullanma örneği de şu şekilde olacaktır. Belirli bir kullanıcı tarafından değiştirilmiş “Users” objesinin tüm geçmişini almak için aşağıdaki örnekte olduğu gibi revisionProperty kullanılmalıdır.

 

Hibernate Envers users değişikliği

 

Not; Tüm sorgu seçenekleri ve örnekleri için, aşağıdaki linki verilen “Hibernate_User_Guide” sayfasına göz atabilirsiniz.

Hibernate User Guide