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. 認証済みの GET/POST などを送信するために、curl リクエストを介して送信する必要があるデータはどれですか?
  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'' 
4

2 に答える 2

2

ここでの問題は、次の 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" という 2 つの変数を与えます。見る:

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

于 2013-12-13T14:00:59.703 に答える
0

どのバージョンの Django を使用していますか? 1.5 以降を使用している場合、ユーザー名フィールドの名前が指定されていないという問題が発生している可能性があります。

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

于 2013-12-11T15:14:53.133 に答える