2012-09-19 11 views
11

मॉडल से पहले मेरे नियंत्रक में संशोधित किया गया है ( अपडेट या हटाया गया है) मैं यह सत्यापित करने की कोशिश कर रहा हूं कि उपयोगकर्ता निष्पादित करने वाले उपयोगकर्ता वास्तव में उस ऑब्जेक्ट का मालिक है जिसे वे संशोधित करने का प्रयास कर रहे हैं।मॉडल स्वामित्व जांच

मैं वर्तमान में विधि स्तर पर ऐसा कर रहा हूं और यह थोड़ा अनावश्यक लगता है।

[HttpPost] 
public ActionResult Edit(Notebook notebook) 
{ 
    if (notebook.UserProfileId != WebSecurity.CurrentUserId) { return HttpNotFound(); } 

    if (ModelState.IsValid) 
    { 
     db.Entry(notebook).State = EntityState.Modified; 
     db.SaveChanges(); 
     return RedirectToAction("Index"); 
    } 
    return View(notebook); 
} 

क्या ऐसा करने का एक सामान्य तरीका है जो विभिन्न मॉडलों में पुन: प्रयोज्य हो सकता है?

क्या यह ActionFilter के साथ ऐसा करना संभव है?

उत्तर

2

मैं आपके पास जो समस्या है उसके साथ एक समस्या देख सकता हूं - आप सुरक्षा जांच करने के लिए उपयोगकर्ता इनपुट पर भरोसा कर रहे हैं।

पर विचार करें अपने कोड

if (notebook.UserProfileId != WebSecurity.CurrentUserId) 

नोटबुक बंधन मॉडल से आ गया है। तो UserProfileId मॉडल बाध्यकारी से आया है। और आप काफी खुशी से नकली कर सकते हैं - उदाहरण के लिए मैं अपने लॉगिन से मेल खाने के लिए छिपे हुए UserProfileId के मूल्य को बदलने के लिए फ़ायरफ़ॉक्स के TamperData का उपयोग करता हूं और दूर जाता हूं।

मैं जो कर रहा हूं (नियंत्रक के बजाए एक सेवा में) एक पोस्ट पर है जो एक अद्वितीय आईडी पर आधारित डेटाबेस से रिकॉर्ड वापस खींच रहा है (उदाहरण के लिए 2/उदाहरण 2 का उपयोग करेगा), और फिर जांच User.Identity।मौजूदा मालिक फ़ील्ड के विरुद्ध नाम (अच्छी तरह से, पास पहचान पहचान पैरामीटर) मेरे पास मेरे लौटा डेटाबेस रिकॉर्ड में है।

क्योंकि मैं डेटाबेस से वापस खींचता हूं (भंडार, जो भी हो) एक विशेषता इस के लिए काम नहीं करेगी, और मुझे यकीन नहीं है कि आप वैसे भी एक विशेषता के दृष्टिकोण में सामान्य हो सकते हैं।

public class VerifyOwnership : IActionFilter 
{ 
    public void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     foreach(var parameter in filterContext.ActionParameters) 
     { 
      var owned = paramter.Value as IHaveAnOwner; 
      if(owned != null) 
      {      
       if(owned.OwnerId != WebSecurity.CurrentUserId) 
       { 
        // ... not found or access denied 
       } 
      } 
     } 
    } 

    public void OnActionExecuted(ActionExecutedContext filterContext) 
    { 

    } 
} 

कि नोटबुक जैसे मॉडल मान लिया गया एक विशिष्ट इंटरफ़ेस को लागू: की तरह

+0

जोड़ना नहीं होगा [बाइंड (बहिष्कृत = "UserProfileID")] मॉडल बाध्यकारी द्वारा बदला जा रहा है? आदर्श रूप में मैं एक व्यूमोडेल लौटाना चाहता हूं जिसमें कोई आईडी फ़ील्ड नहीं है और केवल उन लोगों को टेम्पैडाटा या कुछ (संग्रहीत नहीं) में संग्रहीत किया गया है ... – mezmi

+0

हां यह होगा, लेकिन फिर यह कहां से आएगा? :) – blowdart

+0

हाँ, मुझे लगता है कि मैंने वास्तव में यह नहीं सोचा था। जैसे मैंने कहा, मैं एक व्यूमोडेल वापस करना चाहता हूं जिसमें कोई आईडी फ़ील्ड नहीं है, मुझे पता नहीं है कि कॉल के बीच एमवीसी में अस्थायी रूप से उस आईडी को कहां स्टोर करना है - सत्र>:) का उपयोग करने के अलावा .... इस तरह से मैं कर सकता था मेरे पीओसीओ को नियंत्रक को वापस करें और ऑटोमैपर का उपयोग करें या कुछ व्यूमोडेल हाइड्रेट करें। – mezmi

3

फ़िल्टर ठीक दृष्टिकोण की तरह लगता है, लेकिन यह कुछ हद तक सीमित है। यह अच्छा होगा यदि आप इस प्रकार का फ़िल्टर हो सकता था होगा:

[RequireOwnership<Notebook>(n => n.UserProfileId)] 

... लेकिन Attributes सीमित हैं, जिसमें डेटा प्रकार की अनुमति है, और मुझे नहीं लगता कि कि जेनरिक या तो अनुमति दी जाती है। तो तुम एक [RequireOwnership] विशेषता है कि प्रतिबिंब का उपयोग कर मॉडल गुण का निरीक्षण कर काम करता है हो सकता है, या आप इसके बजाय कस्टम सत्यापनकर्ता बना सकते हैं, जहां अपने मॉडल इस तरह दिखता है:

public class Notebook 
{ 
    [MatchesCurrentUserId] 
    public int UserProfileId { get; set; } 
} 

फिर अपने ModelState.IsValid जांच पर्याप्त होना चाहिए।

संपादित करें:

एक अन्य विकल्प मेरे पास आ गई है। आप अपने मॉडल पर एक विशेषता के साथ संयोजन के रूप में एक फ़िल्टर का उपयोग कर सकते हैं (ValidationAttribute होना आवश्यक नहीं है)। फ़िल्टर आपके अनुरोध मॉडल का निरीक्षण कर सकता है और वर्तमान उपयोगकर्ता आईडी की तुलना में [MatchesCurrentUserId] के साथ गुणों की जांच कर सकता है।

+0

मैं सत्यापन प्रमाणीकरण का उपयोग करने के विचार के साथ आगे और आगे गया हूं। मुझे विचार पसंद है लेकिन साथ ही मुझे लगता है कि मुझे एचटीपी 401 अनधिकृत बनाम एक सत्यापन त्रुटि वापस लौटना चाहिए। कोई विचार? – mezmi

+0

अनधिकृत प्रतिक्रिया निश्चित रूप से बेहतर है। आप सत्यापन परिणामों का निरीक्षण कर सकते हैं और यह निर्धारित कर सकते हैं कि 401 प्रतिक्रिया वापस की जानी चाहिए या नहीं। या शायद सत्यापन विशेषता एक अपवाद है कि अंततः एक 401 जवाबी कार्रवाई के लिए अनुवाद होगा फेंक सकता है (जैसे कि शायद फेंकने एक 'HttpException') – Jacob

+0

आह, लेकिन आप उन्हें निरीक्षण करने के लिए तो आप बस फिर नियंत्रक में अधिक कोड लिख रहे हैं तो? – jocull

1

जब मैंने अतीत में इस तरह की चीजें की हैं तो यह वास्तव में बहुत बेहतर नहीं रहा है। हमारी परियोजनाओं के लिए हमारे पास एक विधि होगी जो Notebook ऑब्जेक्ट को स्वीकार करेगी और वर्तमान में लॉग इन उपयोगकर्ता के खिलाफ जांच करेगी।

आप इस विधि को अपने सभी अलग-अलग ऑब्जेक्ट प्रकारों से अधिभारित कर सकते हैं और पहुंच की जांच के लिए एक सतत विधि का उपयोग कर सकते हैं। क्षमा करें, मुझे पता है कि यह सबसे अच्छा तरीका है।

[HttpPost] 
public ActionResult Edit(Notebook notebook) 
{ 
    if(!SessionUser.LoggedInUser.CheckAccess(notebook)) 
     return HttpNotFound(); 

    //Other code... 
} 

पीएस SessionUser एक कस्टम क्लास है जिसे हम मूल रूप से उस समय प्रबंधित करने वाले व्यक्ति को प्रबंधित करने के लिए करते थे। आप कुछ ऐसा लिख ​​सकते हैं लेकिन डिफ़ॉल्ट रूप से .NET में होने की अपेक्षा न करें।

5

एक फिल्टर दृष्टिकोण लग सकता है।

public interface IHaveAnOwner 
{ 
    int OwnerId { get; set; } 
} 

ब्लौडार्ट का एक अच्छा मुद्दा है कि उपयोगकर्ता एक पोस्ट में मालिक आईडी के साथ छेड़छाड़ कर सकता है। मुझे यकीन है कि वे अपने ऑथ टिकट के साथ भी छेड़छाड़ कर सकते हैं, लेकिन उन्हें किसी अन्य उपयोगकर्ता के लिए मेल खाने के लिए दोनों उपयोगकर्ता के टिकट और छेड़छाड़ करना होगा, मुझे विश्वास है।

+0

यह एक अच्छा समाधान है - मुझे नव निर्मित वस्तुओं और कुछ अन्य कैच के आसपास कोड करना होगा, मुझे यकीन है – jocull

संबंधित मुद्दे