MVC'de bir model doğrulama işlemini yapmalı mı?


25

MVC modelini kullanmak için geliştirdiğim bir web uygulamasını yeniden tasarlamaya çalışıyorum, ancak modelin geçerliliği kontrol edilip edilmemesi gerektiğinden emin değilim. Örneğin, şu modellerden birini böyle kuruyorum:

class AM_Products extends AM_Object 
{
    public function save( $new_data = array() ) 
    {
        // Save code
    }
}

İlk Soru: Yani, kaydetme yöntemimin $ new_data üzerinde bir doğrulama işlevi çağırması mı yoksa verilerin zaten doğrulanmış olduğunu varsayması mı gerektiğini merak ediyorum.

Ayrıca, doğrulama sunacak olsaydı, veri türlerini tanımlamak için bazı model kodlarının şöyle görüneceğini düşünüyorum:

class AM_Products extends AM_Object
{
    protected function init() // Called by __construct in AM_Object
    {
        // This would match up to the database column `age`
        register_property( 'age', 'Age', array( 'type' => 'int', 'min' => 10, 'max' => 30 ) ); 
    }
}

İkinci Soru: Her AM_Object sınıfı, belirli bir nesnenin veritabanındaki her sütun için register_property'yi çalıştırır. Bunun yapmanın iyi bir yolu olup olmadığından emin değilim.

Üçüncü Soru: Doğrulama model tarafından yapılmalıysa, bir hata mesajı veya hata kodu döndürmeli ve görünümün uygun mesajı görüntülemek için kodu kullanması gerekir mi?

Yanıtlar:


30

İlk Cevap: Modelin kilit rolü bütünlüğü korumaktır. Bununla birlikte, kullanıcı girişi işleme bir denetleyicinin sorumluluğundadır.

Yani, denetleyici kullanıcı verilerini (çoğu zaman sadece dizeler olan) anlamlı bir şeye çevirmelidir. Bu ayrıştırma gerektirir (ve örneğin, farklı ondalık operatörler olduğu için yerel ayarlara bağlı olabilir).
Bu nedenle, gerçek doğrulama, "iyi oluşturuluyor mu?" Şeklinde olduğu gibi, denetleyici tarafından yapılmalıdır. Ancak, doğrulama "veriler anlamlı mı?" Model içerisinde yapılmalıdır.

Bunu bir örnekle açıklığa kavuşturmak için:
Uygulamanızın, bazı tarihler eklemenizi sağladığını varsayalım ( örneğin , bitiş çizgisine sahip bir sorun). Tarihlerin yalnızca Unix zaman damgaları olarak gösterilebileceği bir API'niz olabilir; bir HTML sayfasından geldiğinde, MM / DD / YYYY biçiminde farklı değerler kümesi veya bir dize olacaktır. Bu bilgiyi modelde istemiyorsunuz. Her denetleyicinin ayrı ayrı tarihi anlamaya çalışmasını istiyorsunuz. Bununla birlikte, tarih modele geçildiğinde, model bütünlüğünü korumalıdır. Örneğin, geçmişte veya tatillerde / pazar günlerinde vb. Tarihlere izin vermemek mantıklı olabilir.

Kontrol cihazınız giriş (işlem) kurallarını içerir. Modelinizde iş kuralları var. Ne olursa olsun, iş kurallarınızın daima uygulanmasını istiyorsunuz. Denetleyicide iş kurallarınız olduğunu varsayarsak, daha sonra farklı bir denetleyici oluşturursanız, onları çoğaltmanız gerekir.

İkinci Cevap: Yaklaşım anlamlı olsa da, yöntem daha güçlü hale getirilebilir. Bir dizi olan son parametre yerine, bunun bir örneği olması gerekir IContstraint:

interface IConstraint {
     function test($value);//returns bool
}

Ve rakamlar için,

class NumConstraint {
    var $grain;
    var $min;
    var $max;
    function __construct($grain = 1, $min = NULL, $max = NULL) {
         if ($min === NULL) $min = INT_MIN;
         if ($max === NULL) $max = INT_MAX;
         $this->min = $min;
         $this->max = $max;
         $this->grain = $grain;
    }
    function test($value) {
         return ($value % $this->grain == 0 && $value >= $min && $value <= $max);
    }
}

Ayrıca neyi 'Age'temsil etmek, dürüst olmak gerekirse anlamıyorum . Gerçek mülk adı mı? Varsayılan olarak bir kural olduğunu varsayarak, parametre işlevin sonuna kadar basit bir şekilde gidebilir ve isteğe bağlı olabilir. Ayarlanmazsa, varsayılan olarak DB sütun adının to_camel_case değeri olur.

Böylece örnek çağrı şöyle görünür:

register_property('age', new NumConstraint(1, 10, 30));

Arabirimleri kullanmanın amacı, gittikçe daha fazla kısıtlama ekleyebilmeniz ve istediğiniz kadar karmaşık olmalarıdır. Bir dizgenin normal ifadeyle eşleşmesi için. Bir tarihin en az 7 gün ileride olması için. Ve bunun gibi.

Üçüncü Cevap: Her Model varlık gibi bir yöntem olmalıdır Result checkValue(string property, mixed value). Kontrolör verileri ayarlamadan önce onu çağırmalıdır . ResultDenetimi başarısız oldu olmadığı hakkında tüm bilgilere sahip ve denetleyici buna göre görünümüne olanlar yaymak böylece yaptım durumda, nedenlerini vermelidir.
Modele yanlış bir değer iletilirse, model yalnızca bir istisna oluşturarak yanıt vermelidir.


Bu yazı için teşekkür ederim. MVC hakkında bir çok şeyi açıklığa kavuşturdu.
AmadeusDrZaius

5

"Back2dos" ile tamamen aynı fikirde değilim: Tavsiyem, kontrolörün modele gönderilmeden önce giriş verilerini doğrulamak için her zaman ayrı bir form / doğrulama katmanı kullanmasıdır.

Teorik bir bakış açısından, model doğrulama güvenilir veriler üzerinde çalışır (dahili sistem durumu) ve giriş doğrulama, güvenilmeyen kaynaklardan gelen veriler üzerinde (kullanım durumu ve kullanıcı ayrıcalıklarına bağlı olarak) bir kez açık bir şekilde çalışırken ideal olarak herhangi bir zamanda tekrarlanabilir olmalıdır.

Bu ayırma, bağımlılık enjeksiyonuyla gevşek bir şekilde birleştirilebilen yeniden kullanılabilir modeller, kontrolörler ve formlar oluşturmayı mümkün kılar. Giriş onaylamayı beyaz liste doğrulaması (“iyi bilinenleri kabul et”) ve model doğrulamasını kara liste doğrulama ("kötü bilinenleri reddet") olarak düşünün. Beyaz liste doğrulaması daha güvenliyken, kara liste doğrulaması model katmanınızın çok özel kullanım durumlarına aşırı derecede kısıtlanmasını önler.

Geçersiz model verileri her zaman bir özel durumun ortaya çıkmasına neden olmalıdır (aksi halde uygulama, hatayı fark etmeden çalışmaya devam edebilir); dış kaynaklardan gelen geçersiz girdi değerleri beklenmeyen, ancak oldukça yaygındır (asla hata yapmayan kullanıcılar alamazsanız).

Ayrıca bakınız: https://lastzero.net/2015/11/why-im-using-a-separate-layer-for-input-data-validation/


Basit olması için, Validator sınıfı bir aile olduğunu ve tüm doğrulama işlemlerinin stratejik bir hiyerarşi ile yapıldığını varsayalım. Beton onaylayıcı çocuklar ayrıca özel onaylayıcılardan oluşabilir: e-posta, telefon numarası, form belirteçleri, captcha, şifre ve diğerleri. Denetleyici giriş doğrulama iki türdür: 1) Bir denetleyicinin ve yöntem / komutun varlığını doğrulamak ve 2) verilerin ön incelemesi (yani HTTP istek yöntemi, kaç veri girişi (Çok fazla? Çok az?)
Anthony Rutledge

Girişlerin sayısı doğrulandıktan sonra, bir HTML formunun tüm denetimleri boş bırakıldığında bir şey göndermediğinden, istek başına giriş sayısının değişebileceğini aklınızda bulundurarak doğru HTML denetimlerinin ada göre gönderildiğini bilmeniz gerekir ( özellikle onay kutuları). Bundan sonra, son ön kontrol giriş büyüklüğü testidir. Bence bu geç değil, erken olmalı . Bir denetleyici doğrulayıcısında miktar, kontrol adı ve temel giriş boyutu kontrolü yapmak, denetleyicideki her komut / yöntem için bir Doğrulayıcıya sahip olmak anlamına gelir. Bunun uygulamanızı daha güvenli hale getirdiğini düşünüyorum.
Anthony Rutledge

Evet kontrol doğrulayıcı bir komut için sıkıca için gerekli bağımsız değişkenleri (varsa) bağlanmış olan model kullanılarak , fakat kontrol kendisi adı geçen referans için kaydetmek olmayacak, kontrol doğrulama . Bu, çoğu girdinin meşru olacağı varsayımıyla ileriye gitmemesi gerektiği için, değerli bir uzlaşmadır. Başvurunuza meşru olmayan erişimi ne kadar çabuk durdurursanız, o kadar iyi olur. Denetleyici doğrulama sınıfında (miktar, ad ve girişlerin maksimum boyutu) yapılması, açıkça kötü niyetli HTTP isteklerini reddetmek için tüm modeli somutlaştırmak zorunda kalmaz.
Anthony Rutledge

En fazla giriş boyutu sorununu ele almadan önce, kodlamanın iyi olduğundan emin olunmalıdır. Her şey göz önüne alındığında, bu iş kapsüllenmiş olsa bile, modelin yapması için çok fazla. Kötü niyetli istekleri reddetmek gereksiz yere pahalı bir hal alıyor. Özet olarak, kontrolör, modele gönderdiklerinden daha fazla sorumluluk alması gerekiyor. Denetleyici seviyesi arızası ölümcül olmalı, 200 OK dışındaki istek sahibine geri dönüş bilgisi verilmemelidir. Etkinliği günlüğe kaydet. Ölümcül bir istisna at. Tüm aktiviteyi sonlandır. Tüm işlemleri en kısa zamanda durdurun.
Anthony Rutledge

Minimum kontroller, maksimum kontroller, doğru kontroller, giriş kodlaması ve maksimum giriş boyutu, isteğin niteliğine göre (bir şekilde veya başka). Bazı insanlar bu beş temel şeyi, bir isteğin yerine getirilmesi gerekip gerekmediğinin belirlenmesi olarak tanımlamamıştır. Bunların hepsi tatmin edici değilse, neden bu bilgiyi modele gönderiyorsunuz? İyi soru.
Anthony Rutledge

3

Evet, model doğrulama yapmalı. Kullanıcı Arabirimi de girişi doğrulamalıdır.

Geçerli değerleri ve durumları belirlemek açıkça modelin sorumluluğudur. Bazen bu tür kurallar sıklıkla değişir. Bu durumda modeli meta verilerden besler ve / veya dekore ederim.


Kullanıcının amacının açıkça kötü niyetli veya hatalı olduğu durumlar? Örneğin, belirli bir HTTP isteğinin yediden (7) giriş değerinden daha fazlasına sahip olmadığı varsayılır, ancak kontrol cihazınızın yetmiş (70) değeri olur. İstek açıkça bozulduğunda, on kez (10x) izin verilen değerlerin modele ulaşmasına gerçekten izin verecek misiniz? Bu durumda, herhangi bir özel değerin durumu değil, söz konusu olan isteğin tamamıdır. Derinlemesine bir savunma stratejisi, modele veri göndermeden önce HTTP isteğinin niteliğinin incelenmesi gerektiğini düşündürür.
Anthony Rutledge,

(devam) Bu şekilde, belirli kullanıcı tarafından sağlanan değerlerin ve durumların geçerli olduğunu kontrol etmiyorsunuz, ancak isteğin toplamının geçerli olduğunu kontrol ediyorsunuz. Henüz o kadar ayrıntılı incelemeye gerek yok. Yağ zaten yüzeyde.
Anthony Rutledge,

(devam) Ön uç doğrulamayı zorlamanın yolu yoktur. Otomatik araçların web uygulamanızla arayüz olarak kullanılabileceği düşünülmelidir.
Anthony Rutledge

(Düşünceden sonra) Modeldeki geçerli değerler ve veri durumları önemlidir, ancak benim tanımlamam gerekenler denetleyiciden gelen isteğin amacına yönelik isabetler . Niyet doğrulamasını reddetmek başvurunuzu daha savunmasız bırakır. Amaç yalnızca iyi (kurallara göre oynama) veya kötü (kuralların dışına çıkma) olabilir. Amaç , giriş üzerindeki temel kontrollerle doğrulanabilir: minimum kontroller, maksimum kontroller, doğru kontroller, giriş kodlaması ve maksimum giriş boyutu. Bu bir ya hep ya hiç teklifidir. Her şey geçer veya istek geçersizdir. Modele bir şey göndermenize gerek yok.
Anthony Rutledge

2

Harika soru!

Dünya çapında web geliştirme açısından, aşağıdakileri de sorarsanız ne olur.

"Bir kullanıcı arabiriminden denetleyiciye hatalı kullanıcı girişi sağlanıyorsa , denetleyici Görünüm'ü bir tür döngüsel döngüde güncellemeli, komutları ve giriş verilerini işlemeden önce doğru olmasını zorlamalı mı? Nasıl? Görünüm normal altında nasıl güncellenir? Koşullar view Bir modele sıkıca bağlanmış bir görünüm var mı? Kullanıcı girişi doğrulama , modelin ana iş mantığı mıdır , yoksa bunun için bir ön çalışma mıdır ve bu nedenle kontrolörün içinde gerçekleşmesi gerekir mi (kullanıcı girişi verileri isteğin bir parçası olduğu için)?

(İyi bir giriş elde edilinceye kadar bir modelin başlatılmasını geciktiren bir gecikme olabilir mi?)

Benim düşüncem, modellerin saf ve bozulmamış bir durumu (mümkün olduğunca) yönetmesi gerektiği, model başlatılmadan önce (ve kesinlikle model girdi verisi alınmadan önce) gerçekleşmesi gereken temel HTTP istek girişi doğrulaması ile numaralandırılmaması gerektiğidir. Durum verilerini yönetmek (kalıcı veya başka şekilde) ve API ilişkileri modelin dünyası olduğundan, temel HTTP istek girişi doğrulamasının denetleyicide gerçekleşmesine izin verin .

Özetleme.

1) Rotanızı doğrulayın (URL’den ayrıştırılır), denetleyici ve yöntem başka bir şey ilerlemeden önce mevcut olmalıdır. Bu, kesinlikle gerçek denetleyiciye ulaşmadan önce ön denetleyici aleminde (Router sınıfı) gerçekleşmelidir. Duh. :-)

2) Bir model birçok girdi verisi kaynağına sahip olabilir: bir HTTP isteği, bir veritabanı, bir dosya, bir API ve evet, bir ağ. Giriş onaylamanızın tümünü modele yerleştirecekseniz, programın işletme gereksinimlerinin HTTP istek girişi onaylama bölümünü göz önünde bulundurursunuz . Dava kapandı.

3) Yine de, eğer HTTP istek girişi iyi değilse, birçok nesneyi somutlaştırmak pahasına gider miyop ! Modeli ve tüm karmaşıklıklarını (evet, belki de API ve DB giriş / çıkış verileri için daha fazla onaylayıcı) başlatmadan önce doğrulayarak (HTTP istek girişi) ** ( istekle gelen ) iyi olup olmadığını öğrenebilirsiniz .

Aşağıdakileri test edin:

a) HTTP istek yöntemi (GET, POST, PUT, PATCH, DELETE ...)

b) Minimum HTML kontrolleri (yeterli var mı?).

c) Maksimum HTML kontrolleri (çok fazla var mı?).

d) Doğru HTML kontrolleri (doğru olanlara sahip misiniz?).

e) Giriş kodlaması (tipik olarak UTF-8? kodlamasıdır).

f) Maksimum giriş boyutu (çılgınca sınırların dışındaki girişlerden biri mi?).

Dizeleri ve dosyaları alabileceğinizi unutmayın, bu nedenle modelin başlatılmasını beklemek, sunucunuza yapılan isteklerde çok pahalıya mal olabilir.

Burada anlattıklarım denetleyiciden gelen isteğin amacına isabet ediyor . Niyet doğrulamasını reddetmek başvurunuzu daha savunmasız bırakır. Amaç sadece iyi (temel kurallarınla ​​oynayarak) veya kötü (temel kuralların dışına çıkarak) olabilir.

Niyet , bir HTTP isteği için bir ya hep ya hiç bir teklif. Her şey geçer veya istek geçersizdir . Modele bir şey göndermenize gerek yok.

Bu temel HTTP isteği amacı , normal kullanıcı girişi hataları ve doğrulama ile ilgisi yoktur. Uygulamalarımda, bir HTTP isteğinin onurlandırmamı sağlamak için yukarıdaki beş şekilde geçerli olması gerekir. Bir de savunma derinlemesine eğer konuşma yolu, sunucu tarafında kullanıcı girişi doğrulama için asla herhangi bunlar beş şey başarısız olur.

Evet, bu, dosya girişinin bile, kullanıcıya kabul edilen maksimum dosya boyutunu doğrulama ve söyleme girişimlerinize uygun olması gerektiği anlamına gelir. Sadece HTML mi? JavaScript yok mu? Tamam, ancak kullanıcı çok büyük dosyaların yüklenmesinin sonuçlarından haberdar olmalı (temelde, tüm form verilerini kaybedecekleri ve sistemden atılacakları).

4) Bu, HTTP istek girişi verilerinin uygulamanın iş mantığının bir parçası olmadığı anlamına mı geliyor ? Hayır, bu sadece bilgisayarların sınırlı aygıtlar olduğu ve kaynakların akıllıca kullanılması gerektiği anlamına gelir. Kötü niyetli etkinlikleri daha sonra değil, daha erken durdurmak mantıklıdır. Daha sonra durdurmak için beklemek hesaplama kaynaklarında daha fazla ödeme yaparsınız.

5) HTTP istek girişi kötüyse, isteğin tamamı kötüdür . Ben böyle bakıyorum. İyi HTTP isteği girişinin tanımı, modelin iş gereksinimlerinden türetilmiştir, ancak bir miktar kaynak sınırlaması olması gerekir. Kötü bir isteğin onu öldürmeden ve "Ah, hey, boşver. Kötü istek." Demeden ne kadar süre önce yaşamasına izin vereceksin?

Karar basitçe kullanıcının makul bir giriş hatası yapmış olması değil, bir HTTP isteğinin kötü niyetli ilan edilmesi ve derhal durdurulması gereken sınırların dışında olması.

6) Yani, benim param için, HTTP isteği (YÖNTEM, URL / rota ve veri) ya TÜM iyidir ya da başka bir şey yapamaz. Sağlam bir model zaten kendisiyle ilgilenmek için onaylama görevlerine sahiptir, ancak iyi bir kaynak çobanı “Benim yolum ya da yüksek yol. Doğru gelin ya da hiç gelmeyin” der.

Bu senin programın. “Bunu yapmanın birden fazla yolu var.” Bazı yollar zamana ve paraya diğerlerinden daha pahalı. Daha sonra (modelde) HTTP istek verilerinin doğrulanması bir uygulamanın kullanım ömrü boyunca daha pahalıya mal olmalıdır (özellikle yukarı veya aşağı ölçeklendirme yapıyorsa).

Doğrulayıcılarınız modüler ise, denetleyicideki temel * HTTP istek girişinin ** doğrulanması bir sorun olmamalıdır. Doğrulayıcıların bazen özel onaylayıcılardan da oluştuğu, e-posta, telefon, form belirteçleri, captcha, ...) yalnızca stratejili bir Validator sınıfı kullanın.

Bazıları bunu tamamen yanlış yönlendiriyor gibi görüyor, ancak Dörtlü Çete Tasarım Desenleri: Yeniden Kullanılabilir Nesneye Yönelik Yazılım Öğeleri yazarken, HTTP başlangıç ​​aşamasındaydı .

================================================== ========================

Şimdi, normal kullanıcı girişi doğrulaması ile ilgili olduğu için (HTTP isteği geçerli kabul edildikten sonra), kullanıcı düşünmeniz gereken mesajlaşırken görünümü güncelliyor! Bu tür bir kullanıcı girişi doğrulaması modelde yapılmalıdır.

Ön uçta JavaScript garantisi yoktur. Bu, uygulamanızın kullanıcı arayüzünün hata durumlarıyla senkronize edilmemesini garanti edemezsiniz. Gerçek aşamalı geliştirme, senkronize kullanım durumlarını da kapsayacaktır.

Eşzamanlı kullanım durumunun hesaba katılması, art arda kaybedilen bir sanattır, çünkü bazı insanlar zaman içinde ve uğraşmak istemezler; , arka uçtaki hata göstergeleri, hata mesajları (genellikle dizilerdeki durumu takip ederek).

Güncelleme : Şemada, Viewreferans olması gerektiğini söylüyorum Model. Hayır veri geçmelidir Viewgelen Modelgevşek bağlantı korumak için. görüntü tanımını buraya girin

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.