Отправить аутентифицированный POST-запрос на tastypie - PullRequest
4 голосов
/ 22 августа 2011

Я пытаюсь отправить POST-запрос с использованием ApiKey в APIСПОЗИТОМ ДЛЯ ВСПЫШКИ

моей модели:

class Thing(models.Model):
    name = models.TextField()

    def __unicode__(self):
        return u'%s'%self.name

моего ресурса Model

class ThingResource(ModelResource):
    class Meta:
        queryset = Thing.objects.all()
        resource_name="thing"
        authentication = ApiKeyAuthentication()
        authorization = DjangoAuthorization()

моих URLpy

from django.conf.urls.defaults import patterns, include, url

from tastypie.api import Api
from myapp.api import ThingResource

mobile_api = Api(api_name='mobile')
mobile_api.register(ThingResource())

from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
    url(r'^admin/', include(admin.site.urls)),

    (r'^api/', include(mobile_api.urls)),
)

и моя команда cURL

curl --dump-header - -H "Accept: application/json" -H "Content-Type: application/json"  -d"username=vikingosegundo" -d"api_key=12345" -X POST --data "{\"name\":\"arrrg\"}" http://localhost:8000/api/mobile/thing/

Ответ

{"error_message": "No JSON object could be decoded", 
 "traceback": "Traceback (most recent call last):\n\n  
    File \"/Users/vikingosegundo/Coding/Project/serverside/mysite/tastypie/resources.py\", line 178, in wrapper\n    response = callback(request, *args, **kwargs)\n\n
    File \"/Users/vikingosegundo/Coding/Project/serverside/mysite/tastypie/resources.py\", line 379, in dispatch_list\n    return self.dispatch('list', request, **kwargs)\n\n  
    File \"/Users/vikingosegundo/Coding/Project/serverside/mysite/tastypie/resources.py\", line 409, in dispatch\n    response = method(request, **kwargs)\n\n  
    File \"/Users/vikingosegundo/Coding/Project/serverside/mysite/tastypie/resources.py\", line 1077, in post_list\n    deserialized = self.deserialize(request, request.raw_post_data, format=request.META.get('CONTENT_TYPE', 'application/json'))\n\n  
    File \"/Users/vikingosegundo/Coding/Project/serverside/mysite/tastypie/resources.py\", line 328, in deserialize\n    deserialized = self._meta.serializer.deserialize(data, format=request.META.get('CONTENT_TYPE', 'application/json'))\n\n
    File \"/Users/vikingosegundo/Coding/Project/serverside/mysite/tastypie/serializers.py\", line 161, in deserialize\n    deserialized = getattr(self, \"from_%s\" % desired_format)(content)\n\n  
    File \"/Users/vikingosegundo/Coding/Project/serverside/mysite/tastypie/serializers.py\", line 305, in from_json\n    return simplejson.loads(content)\n\n  
    File \"/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/json/__init__.py\", line 307, in loads\n    return _default_decoder.decode(s)\n\n  
    File \"/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/json/decoder.py\", line 319, in decode\n    obj, end = self.raw_decode(s, idx=_w(s, 0).end())\n\n  
    File \"/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/json/decoder.py\", line 338, in raw_decode\n    raise ValueError(\"No JSON object could be decoded\")\n\n
    ValueError: No JSON object could be decoded\n"
}

Что я делаю не так? Как мне указатьвкусный пирог к объекту json?Кажется, что работает auth + auth.

Ответы [ 2 ]

9 голосов
/ 22 августа 2011

Использование -d и --data с curl искажает данные POST.

Включение параметров username и api_key в GET должно решить эту проблему следующим образом:

    curl --dump-header - -H "Accept: application/json"\
    -H "Content-Type: application/json"  -X POST\
    --data "{\"name\":\"arrrg\"}"\
    "http://localhost:8000/api/mobile/thing/?username=vikingosegundo&api_key=12345"
6 голосов
/ 25 августа 2011

Я хочу добавить ответ сам. Вместо решения Джоша я не добавляю учетные данные в качестве GET -параметров, а передаю их как пользовательские заголовки HTTP.

class CustomApiKeyAuthentication(ApiKeyAuthentication):
    def is_authenticated(self, request, **kwargs):
        username =  request.META.get('HTTP_X_MYAPP_USERNAME')   or request.GET.get('username')
        api_key =   request.META.get('HTTP_X_MYAPP_APIKEY')     or request.GET.get('apikey')

        if not username or not api_key:
            return self._unauthorized()
        try:
            user = User.objects.get(username=username)
        except (User.DoesNotExist, User.MultipleObjectsReturned):
            return self._unauthorized()
        request.user = user
        return self.get_key(user, api_key)


class ThingResource(MopedModelResource):
    creator     = fields.ForeignKey(UserResource, 'creator',    full = not True)
    class Meta:
        queryset        = Thing.objects.all()
        resource_name   = "thing"
        authentication  = CustomApiKeyAuthentication()
        authorization   = ThingAuthorization()

Теперь мы можем добавить X-MYAPP-USERNAME и X-MYAPP-APIKEY к запросу.
Здесь обычный сеанс Telnet, используя GET

GET /api/mobile/thing/ HTTP/1.1
X-MYAPP-APIKEY: 12345
X-MYAPP-USERNAME: vikingosegundo

HTTP/1.0 200 OK
Date: Wed, 24 Aug 2011 19:37:05 GMT
Server: WSGIServer/0.1 Python/2.7.1
Content-Type: application/json; charset=utf-8

{"meta": {"limit": 20, "next": null, …

и сеанс для POST:

POST /api/mobile/thing/ HTTP/1.1
Content-Type: application/json
Content-Length: 49  
X-MYAPP-APIKEY: 12345
X-MYAPP-USERNAME: vikingosegundo

{"name":"qwerty","creator":"/api/mobile/user/1/"}
HTTP/1.0 201 CREATED
Date: Wed, 24 Aug 2011 20:12:32 GMT
Server: WSGIServer/0.1 Python/2.7.1
Content-Type: text/html; charset=utf-8
Location: http://1.0.0.127.in-addr.arpa:8000/api/mobile/thing/8/

И поскольку мы также проверяем GET-параметры, если заголовок не указан, это также работает:

http://localhost:8000/api/mobile/thing/?username=vikingosegundo;apikey=12345;format=json
...