2013-03-27 2 views
1

tastypie 0.9.12 이상으로 레코드 수준 인증을 구현하는 데 문제가 있습니다.Django Tastypie 레코드 수준 인증

내 설정이 같은 같습니다

모델을

class UserProfile(models.Model): 
    def __unicode__(self): 
     return self.user.get_full_name() 

    user = models.OneToOneField(User) 

class Sample(models.Model): 
    def __unicode__(self): 
     return '%s' % self.id 

    OPEN = 0 
    CLAIMED = 1 
    CLOSED = 2 
    MANUAL = 3 
    MODIFIED = 4 
    DELETED = 5 
    ERROR = 6 
    RESERVED = 7 
    STATUS_CHOICES = (
     (OPEN, 'Open'), 
     (CLAIMED, 'Claimed'), 
     (CLOSED, 'Closed'), 
     (MANUAL, 'Manual'), 
     (MODIFIED, 'Modified'), 
     (DELETED, 'Deleted'), 
     (ERROR, 'Error'), 
     (RESERVED, 'Reserved'), 
    ) 

    status = models.SmallIntegerField(max_length = 1, default = OPEN, choices = STATUS_CHOICES) 
    user_profile = models.ForeignKey(UserProfile, blank = True, null = True) 

자원

class BaseResource(ModelResource): 
    # Base class with rather strict default settings 
    # All other Resources extend this and override any defaults to higher permissions 
    class Meta: 
     authentication = DjangoAuthentication() 
     authorization = ReadOnlyAuthorization() 
     allowed_methods = [] 

class SampleResource(BaseResource): # BaseResource defines a default Meta, setting allowed_methods and authentication for all other resources in the API 
    UserProfile = fields.ForeignKey(UserProfileResource, 'user_profile', null = True, full = True) 
    class Meta(BaseResource.Meta): 
     queryset = Sample.objects.all() 
     resource_name = 'sample' 
     allowed_methods = ['get', 'post', 'put', 'patch'] 
     authorization = SampleAuthorization() 
     always_return_data = True 

    def dehydrate_status(self, bundle): 
     return Sample.STATUS_CHOICES[bundle.data['status']][1] 

    def hydrate_status(self, bundle): 
     bundle.data['status'] = Sample.__dict__[bundle.data['status'].upper()] 
     return bundle 

인증

class SampleAuthorization(Authorization): 
    # Checks that the records' owner is either None or the logged in user 
    def authorize_user(self, bundle): 
     return bundle.obj.user_profile in (None, self.user_profile(bundle)) 

    def user_profile(self, bundle): 
     return user_profile.objects.get(user = bundle.request.user) 



    def read_list(self, object_list, bundle): 
     print 'Read List' 
     return object_list.filter(Q(user_profile = self.user_profile(bundle)) | Q(user_profile = None)) 

    def read_detail(self, object_list, bundle): 
     print 'Read Detail' 
     return self.authorize_user(bundle) 

    def create_list(self, object_list, bundle): 
     return object_list 

    def create_detail(self, object_list, bundle): 
     return self.authorize_user(bundle) 

    def update_list(self, object_list, bundle): 
     print 'Update List' 
     allowed = [] 
     for obj in object_list: 
      if obj.user_profile in (None, self.user_profile(bundle)): 
       allowed.append(obj) 

     return allowed 

    def update_detail(self, object_list, bundle): 
     print 'Update Detail' 
     print bundle.obj.status, bundle.data['status'] 
     # Compare status stored on the server against the user-set status 
     # If server status is >= user status 
     # Raise Unauthorized 
     if bundle.obj.status >= bundle.data['status']: 
       raise Unauthorized('New status must be higher than current status') 
     return self.authorize_user(bundle) 

    def delete_list(self, object_list, bundle): 
     raise Unauthorized('Deletion not allowed through API') 

    def delete_detail(self, object_list, bundle): 
     raise Unauthorized('Deletion not allowed through API') 

내 문제는 update_detail이 다른 입력으로 두 번 호출된다는 것입니다. 요청한 업데이트가 서버에 저장된 레코드의 상태를 변경하려고합니다. 새 상태가 저장된 상태보다 높거나 변경이 승인되지 않았습니다.

제 패스
Read Detail 
Update Detail 
0 Claimed 
Update Detail 
1 1 
[27/Mar/2013 09:35:23] "PATCH /api/1.0/sample/1/ HTTP/1.1" 401 0 

에서, bundle.obj.status 올바른 값을 가지지 만 bundle.data [ '상태'] 가지고

상기 코드를 실행

내 출력은 다음과 같다 수화되지 않았어. 두 번째 단계에서 bundle.obj.status가 새 상태로 변경되고 새 상태가 수화되었습니다.

상태가 첫 번째 패스에서 수화되지 않았기 때문에 안정적으로 상태를 비교할 수 없으며 백그라운드에서 완료된 전체 수화물 프로세스를 망칠 수 있으므로 hydrate_status를 수동으로 호출하고 싶지는 않습니다. 두 번째 패스의 값이 동일하므로 아무 상태로 설정하더라도 권한없는 예외가 항상 발생합니다.

저장 및 새 상태 값 모두에 대해 입력이 다른 Tastypie에 의해 메서드가 두 번 호출되는 경우 어떻게 레코드 수준의 인증을 구현할 수 있습니까?

답변

1

가 update_detail에 다수의 호출이 tastypie 프레임 워크의 버그했다, 알고 보니 다음 인증 클래스와 같은 뭔가 좋은 시작이 될 것입니다.

github에서 문제가 제기되어 bug fix으로 해결되었습니다.