2013-12-11 185 views
3

因此,似乎我可以在瀏覽器中執行此操作,但似乎無法通過CURL進行復制。任何關於如何工作的指針都非常感謝。使用會話認證通過捲曲進行身份驗證

我執行此要求登錄用戶:

curl -X POST -H "Content-Type: application/json" \ 
-d '{"username":"tester", "password":"password"}' --verbose \ 
http://localhost:8000/api/user/login/ 

和響應似乎表明請求成功:

* About to connect() to localhost port 8000 (#0) 
* Trying 127.0.0.1... connected 
> POST /api/user/login/ HTTP/1.1 
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3 
> Host: localhost:8000 
> Accept: */* 
> Content-Type: application/json 
> Content-Length: 44 
> 
* upload completely sent off: 44out of 44 bytes 
< HTTP/1.1 200 OK 
< Server: nginx/1.1.19 
< Date: Wed, 11 Dec 2013 12:31:34 GMT 
< Content-Type: application/json 
< Transfer-Encoding: chunked 
< Connection: keep-alive 
< Vary: Accept, Cookie 
< Set-Cookie: csrftoken=h4tjM6o3QyelsAvUhdqNJPinZRdJyrBz; Path=/ 
< Set-Cookie: sessionid=4tsny8kcl7j9x7icr6vptnq1ims89tzr; expires=Wed, 25-Dec-2013 12:31:34 GMT; httponly; Max-Age=1209600; Path=/ 
< 
* Connection #0 to host localhost left intact 
* Closing connection #0 
{"success": true, "username": "tester"} 

如果我只包括CSRF令牌在我的驗證請求,我得到一個401.但是,如果我包含CSRF令牌和會話ID,我會遇到某種Python錯誤。例如:

curl -X GET -H "Content-Type: application/json" -H \ 
"X-CSRFToken: h4tjM6o3QyelsAvUhdqNJPinZRdJyrBz" --cookie \ 
"sessionid=4tsny8kcl7j9x7icr6vptnq1ims89tzr" --verbose \ 
http://localhost:8000/api/user/ | python -mjson.tool \ 

我從服務器上得到的結果:

{ 
    "error_message": "getattr(): attribute name must be string", 
    "traceback": "Traceback (most recent call last): 
File \"/opt/phaidra/env/local/lib/python2.7/site-packages/tastypie/resources.py\", line 195, in wrapper\n response = callback(request, *args, **kwargs)\n\n 
File \"/opt/phaidra/env/local/lib/python2.7/site-packages/tastypie/resources.py\", line 426, in dispatch_list\n return self.dispatch('list', request, **kwargs)\n\n 
File \"/opt/phaidra/env/local/lib/python2.7/site-packages/tastypie/resources.py\", line 454, in dispatch\n self.throttle_check(request)\n\n 
File \"/opt/phaidra/env/local/lib/python2.7/site-packages/tastypie/resources.py\", line 551, in throttle_check\n identifier = self._meta.authentication.get_identifier(request)\n\n 
File \"/opt/phaidra/env/local/lib/python2.7/site-packages/tastypie/authentication.py\", line 515, in get_identifier\n return request._authentication_backend.get_identifier(request)\n\n 
File \"/opt/phaidra/env/local/lib/python2.7/site-packages/tastypie/authentication.py\", line 283, in get_identifier\n return getattr(request.user, username_field)\n\n 
TypeError: getattr(): attribute name must be string\n" 
} 

在錯誤的路線尋找,沒有特別照明。由於這個錯誤不會發生,除非使用--cookie,我假設它嘗試錯誤地解析cookie參數。

還應該指出,我正在使用Neo4django,我相信它不能使用API​​密鑰身份驗證。我的用戶的代碼是這樣的:

class UserResource(ModelResource): 
    class Meta: 
     queryset = AppUser.objects.all() 
     resource_name = 'user' 
     fields = ['first_name', 'last_name', 'username', 'email', 'is_staff'] 
     allowed_methods = ['get', 'post', 'patch'] 
     always_return_data = True 
     authentication = MultiAuthentication(SessionAuthentication(), BasicAuthentication()) 
     authorization = Authorization() 

    def prepend_urls(self): 
     params = (self._meta.resource_name, trailing_slash()) 
     return [ 
      url(r"^(?P<resource_name>%s)/login%s$" % params, self.wrap_view('login'), name="api_login"), 
      url(r"^(?P<resource_name>%s)/logout%s$" % params, self.wrap_view('logout'), name="api_logout") 
    ] 

    def login(self, request, **kwargs): 
     """ 
     Authenticate a user, create a CSRF token for them, and return the user object as JSON. 
     """ 
     self.method_check(request, allowed=['post']) 

     data = self.deserialize(request, request.raw_post_data, format=request.META.get('CONTENT_TYPE', 'application/json')) 

     username = data.get('username', '') 
     password = data.get('password', '') 

     if username == '' or password == '': 
      return self.create_response(request, { 
       'success': False, 
       'error_message': 'Missing username or password' 
      }) 

     user = authenticate(username=username, password=password) 

     if user: 
      if user.is_active: 
       login(request, user) 
       response = self.create_response(request, { 
        'success': True, 
        'username': user.username 
       }) 
       response.set_cookie("csrftoken", get_new_csrf_key()) 
       return response 
      else: 
       return self.create_response(request, { 
        'success': False, 
        'reason': 'disabled', 
       }, HttpForbidden) 
     else: 
      return self.create_response(request, { 
       'success': False, 
       'error_message': 'Incorrect username or password' 
      }) 

def read_list(self, object_list, bundle): 
     """ 
     Allow the endpoint for the User Resource to display only the logged in user's information 
     """ 
     self.is_authenticated(request) 
     return object_list.filter(pk=bundle.request.user.id) 

(您可以查看該文件的全部內容,如果需要,在https://github.com/OpenPhilology/phaidra/blob/master/api/api.py

因此,簡言之,主要問題/混淆點對我來說:

  1. 哪些數據必須通過curl請求發送以發送經過驗證的GET/POST/etc?
  2. 用戶資源的認證值是否正確?
  3. 我應該能夠僅使用CSRF令牌進行身份驗證,還是會話ID也是必需的?

在此先感謝您對此的任何見解!編輯: 這是我們的自定義用戶模型。

from django.contrib.auth import authenticate 

from django.db import models as django_models 
from neo4django.db import models 
from neo4django.graph_auth.models import User, UserManager 


class AppUser(User): 
    objects = UserManager() 

    USERNAME_FIELD = 'username' 

    def __unicode__(self): 
     return unicode(self.username) or u'' 

回答

2

這裏的問題最終是雙重的:

我發現Django函數get_user_model()失敗 - 在幾個地方使用 - 但是而不是,因爲USERNAME_FIELD爲空。如果我將這些值硬編碼到這個文件中,一切正常。問題在於它失敗了,因爲Django需要一個非常具體的自定義用戶模型的命名方案。從Django文檔:

這點對介紹Django應用程序的名稱(必須是在你的INSTALLED_APPS ),和Django的模型,你 希望爲您的用戶模型中使用的名稱。

https://docs.djangoproject.com/en/dev/topics/auth/customizing/#substituting-a-custom-user-model

然而,這並不是故事的全部。 Django假定你的AUTH_USER_MODEL可以被中間的句點分開,這會給它兩個變量,「app_label」和「model_name」。參見:

def get_user_model(): 
    "Return the User model that is active in this project" 
    from django.conf import settings 
    from django.db.models import get_model 

    try: 
     app_label, model_name = settings.AUTH_USER_MODEL.split('.') 
    except ValueError: 
     raise ImproperlyConfigured("AUTH_USER_MODEL must be of the form 'app_label.model_name'") 
    user_model = get_model(app_label, model_name) 
    if user_model is None: 
     raise ImproperlyConfigured("AUTH_USER_MODEL refers to model '%s' that has not been installed" % settings.AUTH_USER_MODEL) 
    return user_model 

(in file: django/contrib/auth/__init__.py) 

但是,我可以通過'from core.models.user import AppUser'訪問我的地址。我不得不扁平化我的項目結構,所以我有一個名爲「app」的應用程序,我的所有模型都放在名爲「models.py」的文件中,然後在settings.py中,我可以將我的AUTH_USER_MODEL設置爲「app.AppUser」。

關於此問題的一個奇怪的部分:在許多其他情況下,即使在我的APP_USER_MODEL被設置爲'core.models.user.AppUser'的情況下,我也能夠通過API登錄。只有當我嘗試使用SessionAuth時,我遇到了問題。

此外,最近Neo4Django的更改也必須升級,因爲他們直接處理圖形驗證。以前,backends.py不是屬性導入,而是嘗試使用我的自定義模型。現在確實如此。具體來說,這個文件:

https://github.com/scholrly/neo4django/blob/9058c0b6f4eb9d23c2a87044f0661f8178b80b12/neo4django/graph_auth/backends.py

0

您使用的是哪個版本的Django?如果您使用1.5或以上,你可能會運行到哪裏都不指定您的用戶名字段的名稱是一個問題:

https://github.com/toastdriven/django-tastypie/blob/master/tastypie/compat.py

+0

你會如何建議我檢查這是否是錯誤?將Django升級到最新版本?我正在使用Django 1.5.3。謝謝! –

+0

看起來您正在使用自定義用戶模型,但您未設置USERNAME_FIELD https://docs.djangoproject.com/en/dev/topics/auth/customizing/#auth-custom-user – dragonx

+0

我已更新原始帖子包含USERNAME_FIELD常量的更新用戶模型,但似乎沒有效果? –

相關問題