項目演化系列--驗證體系

前言html

  數據驗證主要分紅2個部分,一個是前端js對用戶輸入的數據進行檢查,另外一個是後端收到請求時對請求數據進行驗證。有些web項目只在前端驗證用戶的輸入數據,可是對於請求到後端的數據卻沒有進行處理,這會遺留下嚴重的系統漏洞,又或者開發人員分別在先後端編寫驗證代碼,當驗證規則須要調整的時候,就須要一塊兒維護,稍有不慎就會有驗證不一樣步的問題。對於web項目而言,有一個觀念是要重視的,那就是全部請求的數據都是不安全的,由於http是沒有狀態的,請求都是能夠模擬的。前端

  所以這次的文章是在前一篇文章的基礎上增長驗證體系,使開發人員只須要開發後端驗證,經過增長相應的類庫支持能夠直接生成相應的組件html,而前端則須要開發組件來給予支持,雖然實現起來須要很多時間去設計、重構,可是當完成了之後獲益仍是很大的,不只能夠大大縮減須要開發的代碼,並且能夠下降維護的成本。web

  以前我有寫過基於EasyUI的相關擴展,能夠先參考一下:後端

  那麼廢話就很少說了,直接開始吧。安全

前端mvc

  後端類庫能生成的僅僅是前端組件的html,所以必需要先設計好組件,而後根據組件的驗證規則得出相應的html,並根據規則來實現後端類庫。ide

  文章中使用的是基於angular的組件,因爲本人對於html實在不熟悉,所以例子比較簡單,效果就只是改變文本框背景而已,正確的狀況下爲白色,錯誤時爲紅色,html代碼以下:ui

//angular組件
<br type="text" valid-type="驗證規則" data="綁定的值" uc-input />

//實際html
<br type="text" valid-type="['stringLength', { min: 6, max: 12 }]" data="data.name" uc-input />

  該組件的驗證規則是長度驗證:長度介於6-12之間,這裏就不詳細介紹angular的驗證組件實現過程了(稍後再另外寫一篇文章來介紹吧)。this

  有了前端組件的具體格式,接下來即可以着手編碼後端代碼來支持了。編碼

後端

  首先看一下長度驗證類,代碼以下:

//驗證類
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class StringLengthAttribute : Attribute
{
    public int MinLength { get; private set; }

    public int MaxLength { get; private set; }

    public StringLengthAttribute(Int32 maxLength) : this(maxLength, 0) { }

    public StringLengthAttribute(Int32 maxLength, Int32 minLength)
    {
        this.MinLength = minLength;
        this.MaxLength = maxLength;
    }

    public override bool Valid(object value)
    {
        var valueLength = (value ?? string.Empty).ToString().Length;
        return valueLength >= this.MinLength && valueLength <= this.MaxLength;
    }
}

//模型
public class EnterModel
{
    [StringLength(12, 5)]
    public string Name { get; set; }
}

  雖然有模型且模型已經添加了驗證,已經能夠用來生成組件html了,可是有了真實環境中的驗證規則是多種多樣的,所以仍然須要一個接口,提供一個將驗證轉化成thml的方法。

  爲了兼容原來的easyui,因而我新增了相應的angular類去繼承StringLengthAttribute和轉換的接口,代碼以下:

public interface IValidationConverter
{
    string ToHtml();
}

public class AngularStringLengthAttribute : StringLengthAttribute, IValidationConverter
{
    public AngularStringLengthAttribute(int maxLength) : base(maxLength) { }

    public AngularStringLengthAttribute(int maxLength, int minLength) : base(maxLength, minLength) { }

    public string ToHtml()
    {
        var sb = new StringBuilder(" valid-type=\"['stringLength', {");
        return sb.AppendFormat(" min: {0},", this.MinLength)
            .AppendFormat(" max: {0}", this.MaxLength)
            .Append(" }]\"").ToString();
    }
}

  雖然也有方法能夠不增長IValidationConverter接口,直接在生成angular組件的方法中遍歷Attribute並判斷屬於何種驗證類型,可是須要switch來區分,並生成相應的html,這樣就違反了單一責任原則了,所以仍是使用接口比較方便,模型代碼調整以下:

public class EnterModel
{
    [AngularStringLength(12, 5)]
    public string Name { get; set; }
}

  接下來只須要再編寫一個類來生成angular的驗證組件,方法的實現無非就是須要傳入屬性名以及綁定的名稱而已,那麼頁面綁定的方式爲:<%= Angular.Input("屬性名", "綁定名") %>。

  若是想要讓綁定方式支持表達式的話,如:<%= Angular.Input<TModel>(m => m.Name, "綁定名") %>,那麼就須要從表達式中解析出屬性名,《獲取Lambda表達式內表達式的值 》這篇文章有講解。

  以上生成angular組件html的方法這裏就寫了,留給各位來實現了。

  有了以上的驗證支持,接下來只要在mvcHandler內添加相關的驗證支持,上一篇中咱們已經實現從請求中提取路由方法所須要的對象,所以只須要在接下來對該對象進行驗證便可,若是驗證經過則調用路由方法,若是不正確則調用Error,mvcHandler驗證代碼以下:

var isValid = reqType.GetProperties().All(p =>
{
    var attrs = p.GetCustomAttributes(false);
    if (attrs.Length == 0)
        return true;

    return attrs.All(attr =>
    {
        if (attr is IPropertyValidation)
            return (attr as IPropertyValidation).Valid(p.GetValue(req, null));

        return true;
    });
});
if (!isValid) {
    Setting.Error("數據不正確!").ExecuteResult(context);
    return;
}

結束語

  以上大部分的代碼都是能夠放入公用庫的,我只是開了一個頭,後面大部分的工做還要根據具體的項目來進行調整,種類繁多的驗證以及組件,須要開發人員和美工的相互配合才能完成。

  那麼就到這裏了,若是有什麼疑問或者問題,歡迎留言,謝謝。

相關文章
相關標籤/搜索