2009-10-13 34 views
27

Tôi đang sử dụng tính năng xác thực chú thích dữ liệu rộng rãi trong ASP.NET MVC 2. Tính năng mới này đã tiết kiệm rất nhiều thời gian, vì bây giờ tôi có thể xác định cả xác thực phía máy khách và xác thực phía máy chủ ở một nơi. Tuy nhiên, trong khi tôi đã làm một số thử nghiệm chi tiết, tôi nhận ra rằng khá dễ dàng cho một người nào đó bỏ qua xác thực phía máy chủ nếu tôi chỉ dựa vào xác thực Chú thích dữ liệu. Ví dụ: nếu tôi đã xác định trường bắt buộc bằng cách chú thích thuộc tính với thuộc tính [Bắt buộc] và đặt hộp văn bản cho trường bắt buộc đó trong biểu mẫu, người dùng có thể chỉ cần xóa hộp văn bản khỏi DOM (có thể dễ dàng thực hiện thông qua Firebug) và bây giờ việc xác nhận Chú thích dữ liệu sẽ không được kích hoạt trên thuộc tính đó trong khi ModelBinding bên trong một Controller. Để đảm bảo rằng xác nhận "yêu cầu" được kích hoạt, tôi có thể lặp lại xác nhận sau khi ModelBinding xảy ra, nhưng sau đó tôi sẽ lặp lại logic xác nhận của mình.ASP.NET MVC: Xác nhận chú thích dữ liệu có đủ không?

Đề xuất của mọi người về xác thực là gì? Quá trình xác nhận chú thích dữ liệu có đủ không? Hoặc việc xác thực cần được lặp lại để đảm bảo rằng các xác nhận hợp lệ được kích hoạt trong mọi tình huống?

Nhận xét tiếp theo: Dựa trên câu trả lời bên dưới, có vẻ như tôi không thể dựa vào xác nhận Mô hình và Ghi chú dữ liệu một mình. Vì chúng tôi đang kết luận rằng xác thực phía máy chủ bổ sung là bắt buộc, có cách nào dễ dàng cho lớp Dịch vụ của tôi kích hoạt xác thực dựa trên những gì được xác định trong Chú thích dữ liệu không? Dường như điều này sẽ giúp chúng tôi tốt nhất trong cả hai từ ... chúng tôi sẽ không cần phải lặp lại mã xác nhận, nhưng chúng tôi vẫn sẽ đảm bảo rằng xác thực được thực thi ngay cả khi Trình kết hợp mô hình không kích hoạt nó.

Tôi sẽ đăng nhận xét tiếp theo này dưới dạng câu hỏi riêng, vì câu hỏi này đặt ra một câu hỏi khác với câu hỏi ban đầu.

+0

Phản hồi của Koritnik trả lời truy vấn theo dõi của bạn. Tôi thực hiện xác nhận của tôi tương tự như câu trả lời mà anh ấy đã đăng. Cùng một định nghĩa DataAnnotation có thể được sử dụng cho cả xác thực máy chủ và máy khách. –

+1

Xác nhận Chú thích dữ liệu là tốt nếu các thuộc tính xác thực được cung cấp và khung chính nó phù hợp với bạn. Hành vi với Yêu cầu đã được thay đổi cho ASP.NET MVC 2 RTM do phản hồi của cộng đồng, vì vậy [Bắt buộc] hiện hoạt động như bạn mong đợi. Optinally, hãy kiểm tra: Validation Block (Thư viện doanh nghiệp), xVal, NHibernate Validators (được cho là không phụ thuộc vào NHibernate ORM). – miha

+0

'" Tôi sẽ đăng bình luận tiếp theo này như một câu hỏi riêng biệt, vì nó đặt ra một câu hỏi khác với câu hỏi ban đầu. "Một liên kết đến đó không phải là một ý tưởng tồi, eh? – Sinjai

Trả lời

18

Tôi nghĩ là có liên quan đến an ninh cảnh giác bạn nên chọn để bạn xác thực máy chủ ưu tiên và đảm bảo rằng đây luôn là dự phòng của bạn. Xác thực máy chủ của bạn sẽ hoạt động mà không cần xác thực ứng dụng khách. Khách hàng xác nhận là nhiều hơn cho UX và tho đó là tối quan trọng đối với thiết kế của bạn, nó là thứ yếu để bảo mật. Với điều này trong tâm trí bạn sẽ thấy mình lặp đi lặp lại xác nhận của bạn. Mục tiêu thường cố gắng thiết kế ứng dụng của bạn để xác thực máy chủ và khách hàng có thể được tích hợp càng nhiều càng tốt để giảm công việc cần thiết để xác thực trên máy chủ và ứng dụng khách. Nhưng hãy yên tâm bạn phải làm cả hai.

Nếu bỏ qua xác thực máy khách (bằng thao tác DOM), tránh xác thực máy chủ (có vẻ như bạn đang chỉ ra) thì xác thực máy chủ của bạn cho trường hợp này có thể không được sử dụng phù hợp. Bạn nên gọi lại xác thực máy chủ của bạn trong hành động điều khiển của bạn hoặc trong một lớp dịch vụ. Kịch bản bạn mô tả không nên đánh bại xác thực máy chủ của bạn.

Với kịch bản bạn mô tả, phương pháp thuộc tính DataAnnotation phải đủ. Có vẻ như bạn chỉ cần thực hiện một vài thay đổi mã để đảm bảo rằng xác thực máy chủ của bạn cũng được gọi khi gửi biểu mẫu.

2

Chú thích dữ liệu chắc chắn là không đủ. Tôi sử dụng nó rộng rãi cũng để xác nhận trước các cuộc gọi của tôi đến mô hình miền để có được báo cáo lỗi tốt hơn và thất bại càng sớm càng tốt.

Tuy nhiên, bạn có thể tự tinh chỉnh Mô hình chú thích dữ liệu để đảm bảo các thuộc tính có [Bắt buộc] PHẢI được đăng. (sẽ tiếp tục với mã sau ngày hôm nay).

CẬP NHẬT Lấy nguồn cho DataAnnotations Mẫu Binder và tìm dòng này trong DataAnnotationsModelBinder.cs

// Only bind properties that are part of the request 
if (bindingContext.ValueProvider.DoesAnyKeyHavePrefix(fullPropertyKey)) { 

Thay đổi nó để

// Only bind properties that are part of the request 
bool contextHasKey = bindingContext.ValueProvider.DoesAnyKeyHavePrefix(fullPropertyKey); 
bool isRequired = GetValidationAttributes(propertyDescriptor).OfType<RequiredAttribute>().Count() > 0; 
if (contextHasKey || (!contextHasKey && isRequired)) { 
+0

Cảm ơn Martijn. Tôi mong được thấy mã của bạn. –

+0

Chắc chắn, tôi đã đăng bài này trước khi rời đi để làm việc (tại nơi làm việc vẫn còn) nên không có thời gian để viết mã: (Tôi đã sửa đổi phần kết dính trước đó một chút vì nó không kiểm tra các đối tượng lồng nhau và đặt lại các thuộc tính không hợp lệ thành null mà tôi không đồng ý http://stackoverflow.com/questions/820468/how-does-dataannotationsmodelbinder-work-with-custom-viewmodels/864541#864541 Tôi đã thêm Kiểm tra bắt buộc kể từ đó nhưng cũng muốn kiểm tra chúng khi tôi về nhà trước –

+0

Cập nhật với mã, nhưng tôi không ở vị trí để kiểm tra nó ra đúng cách sẽ làm như vậy một lần nữa vào ngày mai nhưng đăng nó lên vì vậy có lẽ bạn có thể đánh giá nó nhanh hơn. Nó vượt qua các bài kiểm tra đơn vị của dự án nhưng công bằng ở đó không có thử nghiệm thử nghiệm trường hợp này: D –

7

Tôi đã ghép nối xVal với DataAnnotations và đã viết bộ lọc Hành động của riêng tôi để kiểm tra bất kỳ thông số loại Thực thể nào cho mục đích xác thực. Vì vậy, nếu một số lĩnh vực là mất tích trong postback, validator này sẽ điền vào ModelState từ điển do đó có mô hình không hợp lệ.

Điều kiện tiên quyết:

  • thực thể của tôi/mô hình các đối tượng thực hiện tất cả các giao diện IObjectValidator mà tuyên bố Validate() phương pháp.
  • lớp thuộc tính của tôi được gọi là ValidateBusinessObjectAttribute
  • xác nhận xval thư viện

đang lọc Hành động:

public void OnActionExecuting(ActionExecutingContext filterContext) 
{ 
    IEnumerable<KeyValuePair<string, object>> parameters = filterContext.ActionParameters.Where<KeyValuePair<string, object>>(p => p.Value.GetType().Equals(this.ObjectType ?? p.Value.GetType()) && p.Value is IObjectValidator); 
    foreach (KeyValuePair<string, object> param in parameters) 
    { 
     object value; 
     if ((value = param.Value) != null) 
     { 
      IEnumerable<ErrorInfo> errors = ((IObjectValidator)value).Validate(); 
      if (errors.Any()) 
      { 
       new RulesException(errors).AddModelStateErrors(filterContext.Controller.ViewData.ModelState, param.Key); 
      } 
     } 
    } 
} 

controller action của tôi được định nghĩa như thế này thì:

[ValidateBusinessObject] 
public ActionResult Register(User user, Company company, RegistrationData registrationData) 
{ 
    if (!this.ModelState.IsValid) 
    { 
     return View(); 
    } 
    ... 
} 
+0

bạn có ví dụ chi tiết hơn về cách sử dụng dự án này hoặc dự án có thể tải xuống có lẽ –

+0

@geocine: Trường hợp có vẻ là vấn đề? Bạn đang sử dụng MVC1? Các phiên bản mới hơn không yêu cầu thực hiện điều này, vì chúng tự động xác thực các tham số kiểu mạnh ... Nhưng ví dụ này ở đây cũng chi tiết như trong thực tế. Vì vậy, nơi có vẻ là vấn đề? –

+0

Tôi vừa mới chuyển qua và tôi mới đọc aspmvc về các vấn đề xác thực. Tôi quên tôi đã sử dụng MVC 2. xấu của tôi. –

2

tôi đã viết ValidationService của riêng tôi cho MVC 1.0 bằng cách sao chép các mẫu từ cả xV DataAnnotationsRuleProvider của al và DataAnnotationsModelBinder của Microsoft (và các bình luận của Martijn). Giao diện dịch vụ là bên dưới:

public interface IValidationService 
{ 
    void Validate(object instance); 

    IEnumerable<ErrorInfo> GetErrors(object instance); 
} 

public abstract class BaseValidationService : IValidationService 
{ 
    public void Validate(object instance) 
    { 
     var errors = GetErrors(instance); 

     if (errors.Any()) 
      throw new RulesException(errors); 
    } 

    public abstract IEnumerable<ErrorInfo> GetErrors(object instance); 
} 

Dịch vụ này là một Á hậu xác nhận rằng đi cây tài sản của trường hợp đối tượng mà nó nhận được và thực sự thực hiện xác nhận các thuộc tính mà nó tìm thấy trên mỗi tài sản, xây dựng một danh sách các đối tượng errorInfo khi các thuộc tính không hợp lệ. (Tôi sẽ đăng toàn bộ nguồn nhưng nó đã được viết cho một khách hàng và tôi chưa biết nếu tôi được phép làm như vậy.)

Sau đó bạn có thể có bộ điều khiển, dịch vụ logic nghiệp vụ yêu cầu xác thực một cách rõ ràng khi bạn đã sẵn sàng, thay vì chỉ dựa vào chất kết dính mô hình để xác nhận.

Có một vài cạm bẫy khác mà bạn cần phải nhận thức:

  • Giá trị mặc định DataTypeAttribute trong dữ liệu chú thích không thực sự làm bất cứ kiểu dữ liệu xác nhận, vì vậy bạn sẽ cần viết thuộc tính mới thực sự sử dụng biểu thức thường xuyên của xVal (hoặc một cái gì đó khác) để thực hiện kiểu dữ liệu phía máy chủ xác thực.
  • xVal không đi bộ thuộc tính để tạo xác thực phía máy khách, vì vậy bạn có thể muốn thực hiện một số thay đổi ở đó để nhận được xác thực hợp lệ phía khách hàng mạnh mẽ hơn.

Nếu tôi được phép và có thời gian, tôi sẽ cố gắng cung cấp thêm nguồn ...

1

Xem CodeProject Server-side Input Validation using Data Annotations

xác nhận đầu vào có thể được thực hiện tự động trên các mặt hàng trong ASP.NET MVC hoặc xác nhận một cách rõ ràng mô hình chống lại các quy tắc. Mẹo này sẽ mô tả cách có thể thực hiện thủ công trên phía máy chủ của các ứng dụng ASP.NET hoặc trong mã vùng lưu trữ của WPF ứng dụng.

 // Use the ValidationContext to validate the Product model against the product data annotations 
     // before saving it to the database 
     var validationContext = new ValidationContext(productViewModel, serviceProvider: null, items:null); 
     var validationResults = new List<ValidationResult>(); 

     var isValid = Validator.TryValidateObject(productViewModel, validationContext,validationResults, true); 
Các vấn đề liên quan