2011-12-26 13 views
9

में POST का उपयोग कर विदेशीकी के साथ समस्याएं मैं django-tastypie का उपयोग कर एक साधारण एपीआई बना रहा हूं।Django-Tastypie

  • एक नोट संसाधन एक नोट एक उपयोगकर्ता द्वारा छोड़ा का प्रतिनिधित्व: विचार मैं दो संसाधन है। केवल उपयोगकर्ता जिसने नोट बनाया है उसे संपादित कर सकते हैं।
  • टिप्पणी संसाधन। टिप्पणियां किसी भी उपयोगकर्ता द्वारा किसी भी नोट पर छोड़ी जा सकती हैं।

टी एल; डॉ: मैं नोट एक नोट के निर्माता को संपादित करते समय अभी तक किसी भी उपयोगकर्ता एक नोट पर टिप्पणी करने के लिए अनुमति को सीमित करने में असमर्थ हूँ।

मैं प्रमाणीकरण के लिए निम्नलिखित सेटअप का उपयोग कर रहा हूँ:

class CreatedByEditAuthorization(Authorization): 
    def is_authorized(self, request, object=None, **kwargs): 
     return True 

    def apply_limits(self, request, object_list): 
     if request and request.method != 'GET' and hasattr(request, 'user'): 
      return object_list.filter(created_by=request.user) 
     return object_list 

संक्षेप में, एक उपयोगकर्ता केवल जिसके लिए वे created_by संपत्ति के बराबर हैं वस्तुओं संपादित करने के लिए अधिकृत किया गया है (वे केवल वस्तुओं वे बनाए संपादित कर सकते हैं) ।

class NoteResource(ModelResource): 
    comments = fields.ToManyField('myapp.api.resources.CommentResource', 'comments', null=True, blank=True) 
    created_by = fields.ToOneField('account.api.resources.UserResource', 'created_by') 

    def obj_create(self, bundle, request, **kwargs): 
     return super(HapResource, self).obj_create(bundle, request, created_by=request.user) 

    class Meta: 
     queryset = Note.objects.all() 
     allowed_methods = ['get', 'put', 'post'] 
     authorization = CreatedByEditAuthorization() 

इसलिए यहाँ, जब एक वस्तु बन जाता है, मैं अपने आप वर्तमान उपयोगकर्ता created_by विशेषता को देते हैं और उचित प्राधिकरण से लिंक:

यह इस प्रकार जुड़ा हुआ है।

Comment संसाधन सरल है और Note संसाधन पर ForeignKey है।

समस्या यह है: यदि उपयोगकर्ता ए नोट बनाता है और उपयोगकर्ता बी उस नोट पर टिप्पणी करने का प्रयास करता है, तो tastypie उस नोट को संपादित करने के लिए एक POST अनुरोध भेजता है (या अनुकरण करता है)। यह प्रयास अस्वीकार कर दिया गया है क्योंकि उपयोगकर्ता बी ने नोट नहीं बनाया है, इसलिए टिप्पणी बनाना विफल हो जाता है।

सवाल यह है: वहाँ एक रास्ता है करने के लिए या तो:

    नोट संसाधन या
  1. बदलें प्राधिकरण योजना के उलट-संबंध बनाने के लिए एक पोस्ट का उपयोग करने से
  2. रोकें tastypie तो नोट्स केवल उनके निर्माता द्वारा संपादित किया जा सकता है, लेकिन टिप्पणियां आम तौर पर बनाई जा सकती हैं?

किसी भी अंतर्दृष्टि के लिए अग्रिम धन्यवाद।

संपादित करें: मेरे पास एक बड़ी वसा हैक है जो इसे पूरा कर सकता है। मुझे यकीन है कि यह सुरक्षित है, लेकिन मैं सकारात्मक नहीं हूं; मैं सुनिश्चित करने के लिए कुछ प्रश्न बनाने का प्रयास करूंगा।

class SafeForeignKey(fields.ForeignKey): 
    def build_related_resource(self, value, request=None, related_obj=None, related_name=None): 
     temp = request.method 
     if isinstance(value, basestring): 
      request.method = 'GET' 
     ret = super(SafeForeignKey, self).build_related_resource(value, request, related_obj, related_name) 
     request.method = temp 
     return ret 

हर बार जब हम इस संबंधित संसाधन के निर्माण के लिए प्रयास करते हैं, हम (एक GET के रूप में अनुरोध निशान के बाद से हम उम्मीद करते हैं यह करने के लिए मिलान किया जा: Comment में fields.ForeignKey का उपयोग कर Note से संबंधित करने के बजाय, मैं एक कस्टम फ़ील्ड बनाने एक SELECTUPDATE की बजाय क्वेरी जो PUT या POST से मेल खाता है)। गलत तरीके से इस्तेमाल होने पर यह वास्तव में बदसूरत और संभावित रूप से असुरक्षित है, और मैं एक बेहतर समाधान की उम्मीद कर रहा हूं।

संपादित करें 2: स्वादिष्ट स्रोत पढ़ने से, जहां तक ​​मैं कह सकता हूं कि क्वेरी द्वारा प्राधिकरण को फ़िल्टर करने का कोई तरीका नहीं है जो वास्तव में भेजा जाएगा।

+0

प्रश्नों के युगल - क्या आप contrib.comments का उपयोग कर रहे हैं? क्या आप प्रमाणीकरण के साथ ही प्राधिकरण का उपयोग कर रहे हैं? मेरे पास एक बहुत ही समान सेटअप प्रतीत होता है (बिना टिप्पणी संसाधन के प्रतीत होता है) जो किसी अन्य उपयोगकर्ता ऑब्जेक्ट पर एक नई टिप्पणी पोस्ट करते समय ठीक काम करता है। – JamesO

+0

@JamesO नहीं, हमारी टिप्पणियां contrib.comments की तुलना में कुछ हद तक समृद्ध हैं (और एक ही समस्या वाले एक पोस्ट से जुड़े अन्य डेटा हैं)। वर्तमान में हम केवल अंतर्निहित प्रमाणीकरण() का उपयोग कर रहे हैं (यानी सभी को प्रमाणित किया गया है)। –

+0

क्या आपने इसे django-tastypie पर एक समस्या के रूप में पोस्ट किया है: https://github.com/toastdriven/django-tastypie/issues? यदि हर बार जब आप इससे संबंधित कुछ बनाते हैं तो यह मूल रूप से अभिभावक रिकॉर्ड को अपडेट करने का प्रयास करता है, यह किसी सुविधा की तुलना में बग के करीब है। –

उत्तर

4

प्रति चर्चा के रूप में https://github.com/toastdriven/django-tastypie/issues/480#issuecomment-5561036 पर:

विधि अगर एक Resource अद्यतन किया जा सकता can_update है निर्धारित करता है कि। इसलिए, "उचित" तरीके से इस काम करने के लिए, आप NoteResource का एक उपवर्ग बनाने की जरूरत: note = fields.ForeignKey(SafeNoteResource, 'note'):

class SafeNoteResource(NoteResource): 
    def can_update(self): 
     return False 
    class Meta: 
     queryset = Note.objects.all() 
     allowed_methods = ['get'] 
     authorization = Authorization() 
     # You MUST set this to the same resource_name as NoteResource 
     resource_name = 'note' 

तो मानक तरीके से नोटों को CommentResource लिंक करते हैं।

1

एक सरल उपाय apply_limits या नहीं, अनुरोध एक नोट संसाधन या एक टिप्पणी संसाधन के लिए है अंदर जांच करने के लिए किया जाना चाहिए। जैसे जैसे

def apply_limits(self, request, object_list): 
    if request and request.method != 'GET' and hasattr(request, 'user') and getattr(request, 'path','').startswith('/api/v1/note'): 
     return object_list.filter(created_by=request.user) 
    return object_list 

कुछ तो फिर तुम केवल एक ही उपयोगकर्ता के लिए नोट्स के लिए उपयोग, अन्य संबंधित संसाधन के माध्यम से सीमित कर रहे हैं जब उपयोगकर्ता संसाधन सीधे एक नोट तक पहुँच रहा है, और नहीं, इस तरह के रूप टिप्पणियाँ

अद्यतन: या एक से थोड़ा अधिक सुरक्षित विकल्प है कि इस अनुरोध के साथ 'एपीआई/v1/टिप्पणी' नहीं शुरू करता है की जाँच करने के होगा - तो आप केवल कुछ भी टिप्पणी के अलावा अन्य के बजाय टिप्पणी करने की एक्सेस श्वेत सूची बनाती रहे हैं । हालांकि वही सिद्धांत लागू होता है। अनुरोध पथ की इस पाठ-आधारित तुलना से सावधान रहें, ऐसे मामलों से बचने के लिए जहां कोई व्यक्ति आपके प्राधिकरण को बाईपास करने के लिए आपके यूआरएल में स्ट्रिंग को जोड़ता/तैयार करता है। उम्मीद है कि प्रीपेडिंग अधिक सीमित है, क्योंकि इसे urls.py में सही यूआरएल हिट करने की जरूरत है, इसलिए मैंने startswith का उपयोग क्यों किया। बेशक आपको अपने tastypie urls से मेल खाने के लिए पथ स्ट्रिंग को समायोजित करना होगा।

+0

यह मैंने जो प्रस्तावित किया है उससे बड़ा हैक लगता है; संवाददाता 'संसाधन' के लिए 'मेटा' में टेबल-स्तरीय अनुमतियों को संभाला जाना चाहिए। इसके अतिरिक्त, जैसा कि आप कहते हैं, पाठ-आधारित तुलना खतरनाक हो सकती है (और वास्तव में, अगर बग्स भी कहें, तो आप 'पूर्ण = सही' के साथ एक टिप्पणी का संबंध लेना चाहते थे - इस मामले में यूआरएल शायद शामिल/टिप्पणी /)।बंडल से क्या पारित किया जाता है, इस अर्थ में, आप सही हैं कि पथ वास्तव में आपके पास एकमात्र प्रासंगिक डेटा है। –

+0

यह सुनिश्चित नहीं है कि मेरा सुझाव POST से GET तक अनुरोध विधि को बदलने से बड़ा हैक (कोड कोड की पंक्तियों का उल्लेख न करें)। मैंने प्रस्तावित समाधान पर, प्राधिकरण को सही जगह (जो लागू_limits है) में संभाला जाता है, और यूआरएल जांच पूरी की जा सकती है या नहीं। हम अनुरोध यूआरएल की जांच कर रहे हैं और कोई बंडल डेटा नहीं। मेरे समाधान को टिप्पणियाँ संसाधन obj_create के अंदर अनुरोध ऑब्जेक्ट में किसी प्रकार का ध्वज जोड़कर थोड़ा सुधार किया जा सकता है और फिर नोट्स apply_limits विधि में इसकी जांच कर सकता है। – gingerlime

+0

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