所以,似乎我可以从浏览器中执行此操作,但我似乎无法通过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)
查看文件的全部内容总而言之,对我而言,主要问题/疑点是:
提前感谢您对此有任何见解!
编辑: 这是我们的自定义用户模型。
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''
答案 0 :(得分: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'。
关于此的奇怪部分:在许多其他情况下,我已经能够通过API登录,即使我的APP_USER_MODEL设置为'core.models.user.AppUser'。它只有当我尝试使用SessionAuth时才会遇到问题。
此外,最近Neo4Django的变化也必须升级,因为它们直接处理图表验证。以前,backends.py不是属性导入并尝试使用我的自定义模型。现在确实如此。具体来说,这个文件:
答案 1 :(得分:0)
您使用的是哪个版本的Django?如果您使用的是1.5或更高版本,则可能会遇到未指定用户名字段名称的问题:
https://github.com/toastdriven/django-tastypie/blob/master/tastypie/compat.py