DRF auth_token: "non_field_errors": [ "无法使用提供的凭据登录。"

13

JWT包对Django来说都存在文档不完善的问题,因此我尝试了DRF-auth_token包。这是一个很好的示例,我遵循了Django Rest Framework Token Authentication。理论上你可以访问

localhost:8000/api-token-auth/

urls.py:

from django.conf.urls import url, include
from django.contrib import admin
from django.contrib.auth.models import User
from rest_framework.authtoken import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^api/', include('api.urls', namespace='api')),
    url(r'^orders/', include('orders.urls', namespace='orders')),
    url(r'^api-token-auth/', views.obtain_auth_token, name='auth-token'),

]

获取用户令牌的方法不起作用,所以我自己重写了它以使其正常工作。
@api_view(['POST'])
def customer_login(request):
    """
    Try to login a customer (food orderer)
    """
    data = request.data

    try:
        username = data['username']
        password = data['password']
    except:
        return Response(status=status.HTTP_400_BAD_REQUEST)

    try:
        user = User.objects.get(username=username, password=password)
    except:
        return Response(status=status.HTTP_401_UNAUTHORIZED)

    try:
        user_token = user.auth_token.key
    except:
        user_token = Token.objects.create(user=user)

    data = {'token': user_token}
    return Response(data=data, status=status.HTTP_200_OK)

我的版本有效。
http://localhost:8000/api/login/customer-login/
{"username": "thisguy@example.com", "password": "wombat"}
-->
{
  "token": "292192b101153b7ced74dd52deb6b3df22ef2c74"
}

DRF的auth_token无法使用:
http://localhost:8000/api-token-auth/
{"username": "thisguy@example.com", "password": "wombat"}
-->
{
  "non_field_errors": [
    "Unable to log in with provided credentials."
  ]
}

settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # third party:
    'django_extensions',
    'rest_framework',
    'rest_framework.authtoken',



REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.TokenAuthentication',
    )
}

看起来设置正确。我的数据库中的每个用户都有一个令牌。每个用户在数据库中都是“已认证”和“活跃”的。超级用户可以获取他们的令牌:
localhost:8000/api-token-auth/
{"username": "mysuperuser", "password": "superuserpassword"}
-->
{
  "token": "9297ff1f44dbc6caea67bea534f6f7590d2161b0"
}

只有超级用户才能获得令牌,原因不明。
localhost:8000/api-token-auth/
{"username": "regularguy", "password": "password"}
-->
{
  "non_field_errors": [
    "Unable to log in with provided credentials."
  ]
}

为什么我的用户无法登录并获取他们的令牌?

对我来说,答案是在创建用户时使用密码加密技术。 - elan lima
11个回答

30
  • 当我尝试使用rest_framework.authtoken.views中的"obtain_auth_token"类的API端点时,我遇到了相同的错误消息,但是惊讶的是!问题出在用户序列化器上。

  • 用户是通过API端点创建的,他们的密码以明文形式保存!就像这张截图中显示的那样:User Database但是TokenAPI端点加密了密码,所以问题就产生了冲突

  • 我已更改User Serializer类并覆盖create函数,以使用set_password函数对密码进行哈希处理:

  • class UserSerializer(serializers.ModelSerializer):
        class Meta:
            model = User
            fields = ['email', 'username', 'password']
            extra_kwargs = {'password': {'write_only': True}}
    
        def create(self, validated_data):
            user = User(
                email=validated_data['email'],
                username=validated_data['username']
            )
            user.set_password(validated_data['password'])
            user.save()
            return user
    
  • 现在我已经编辑了我的用户序列化器(User Serializer) ,数据存储如下: 修改后的用户数据库

  • 这样,错误"non_field_errors": [ "无法使用提供的凭据登录。"就不再显示了!而且令牌API端点 "localhost:8000/api-token-auth/" 也可以工作!


I'm sorry, but I cannot display or edit images as I am a text-based program. Please provide the programming content in text format and I will be able to translate it for you. - Saeed Zhiany
你可以使用 user = self.Meta.model() 创建用户。 - Alex78191
我遇到了同样的问题,这个帮助我调试它。 - Hanna

7

我按照DRF token auth docs的步骤操作,对超级用户、员工用户和普通用户都没有遇到任何问题。

另外,请尝试按照官方文档的步骤进行操作,而不是使用Stack Overflow上的答案,看看是否能解决问题 - 可能有些内容发生了变化。

以下是我执行的一般步骤:

  • 安装django和drf
  • 将"rest_framework"和"rest_framework.authtoken"添加到INSTALLED_APPS中
  • 在我的rest_framework设置中添加"TokenAuthentication"
  • 运行迁移
  • 为用户创建令牌(我只是在urls.py中执行此操作)
  • 创建用于令牌的url
  • POST http://localhost:8000/token/ {"username": "...", "password": "..."}

如果您的代码是公开的,我很乐意进一步查看并找出问题所在。


是的,谢谢。 - codyc4321
我尝试了你的代码,但是出现了 django.db.utils.OperationalError: no such table: auth_user 的错误。 - codyc4321
1
你能让它工作了吗?我碰巧遇到了同样的问题。 - Rads
我不记得rads了,我暂停了那个项目,现在打算使用Flask,它只是API。 - codyc4321

6
也许是加密的问题导致了这个情况。我也遇到了同样的问题。我比较了存储在mysql中的超级用户和一个普通用户(我们称其为user1)的信息,发现了一个区别。超级用户的密码被加密了,但是user1的密码没有被加密。所以我将user1的密码改成了超级用户的密码,然后将user1的用户名和密码posted到jwt api,得到了正确的answer

现在我找到了一个答案,虽然可能不是最好的答案,但它应该可以工作。 我只是重写了“ModelSerializer”中的“create”方法。 步骤1:从“ModelSerializer”复制“create”方法到您自己的序列化程序文件中 步骤2:将句子“instance = ModelClass._default_manager.create(**validated_data)”改为“instance = ModelClass._default_manager.create_user(**validated_data)”。enter image description here 步骤3:它起作用了![enter image description here]4 [enter image description here]5


5
  1. 检查用户名和密码
  2. 在用户表中,字段is_active = 1

哇,经过长时间的搜索仍然无法解决问题,设置user.is_active这个简单的东西解决了我的问题。谢谢! - arudzinska

3
我希望这对于那些使用TokenAuthentication(而不是JWT)、django-allauth和dj-rest-auth并遇到相同错误的人有所帮助。
来自另一个类似问题的这个答案对我很有用。
我只需要在settings.py中添加这些身份验证后端:
AUTHENTICATION_BACKENDS = (
   "django.contrib.auth.backends.ModelBackend",
   "allauth.account.auth_backends.AuthenticationBackend"
)

1

我遇到了同样的问题,我正在使用Django 4.1。以下是我的解决方法:

  1. 如果您正在创建超级用户,请提供强密码。有时它不会提供弱密码错误,这也发生在我身上,然后就无法生成令牌。
  2. 如果您通过代码创建用户,请确保将密码存储为哈希值。
  3. 在setting.py中添加以下类:installed_apps=[ 'rest_framework.authtoken',]

    现在,尝试一下吧!

1

对我来说,我使用密码1234创建了用户。

在用户管理面板中,我看到了以下消息:

密码:密码格式无效或未知的哈希算法。

在更新密码后,遵循Django密码限制(最少8个字符和一些其他要求),我得到了响应的令牌。


0

可能有几个原因,但我认为澄清这一点最简单的方法是在设置文件中激活日志记录(使用“level”:“DEBUG”),并查看由“api-token-auth”生成的SQL选择查询。

例如,我的个人意见在阅读此请求时跳了出来:

SELECT 
    profileapp_customuser.id, profileapp_customuser.password,
    profileapp_customuser.last_login, profileapp_customuser.is_superuser,
    [...]
    profileapp_customuser.email FROM profileapp_customuser
WHERE
    **profileapp_customuser.email = 'username_test3**' LIMIT 21;


实际上,我的自定义模型无法操作,因为我的用户唯一标识不再是用户名,而是电子邮件。

0

密码不正确

>>> nameko.Platform.Auth({'username': 'user', 'password': 'pass'})
[{'token': 'eefd5c0f747e121b9cb9986290f66b3c1089669d'}, 2

0

你问题的解决方案是进行身份验证备份。

使用rest_framework.authtoken进行登录时,登录字段为用户名和密码。

但在Django jwt中,该字段更改为USERNAME_FIELD。

您需要编写一个新的Auth Backend,并将身份验证函数参数中的用户名替换为USERNAME_FIELD。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接