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에 의해 메서드가 두 번 호출되는 경우 어떻게 레코드 수준의 인증을 구현할 수 있습니까?