Django (using TokenAuthentication): “non_field_err

2019-07-03 23:15发布

问题:

I'm using httpie to test my custom authentication.

http POST http://127.0.0.1:8000/api-token-auth/ username='username1' password='Password123'

I did create a custom auth object using AbstractUser.

Using TokenAuthentication, I followed the docs and added my custom TokenAuthentication in my REST_FRAMEWORK settings:

REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
    'regis.models.CustomAuthentication',
    )
}

And added rest_framework.authtoken in my installed apps.

My AUTHENTICATION_BACKEND is as follows:

AUTHENTICATION_BACKENDS = [ 'regis.models.CustomAuthentication' ]

And here is my custom authentication class:

class CustomAuthentication(authentication.TokenAuthentication):
    def authenticate(self, request):
        username = request.META.get('X_USERNAME')
        print(username)
        user_model = get_user_model()
        if not username:
            return None
    try:
        user = user_model.objects.get(username=username)
    except User.DoesNotExist:
        raise exceptions.AuthenticationFailed('No such user')
    return (user, None)

urls.py:

urlpatterns += [
    url(r'^api-token-auth/', views.obtain_auth_token),

    ]

I'm pretty much following the DRF docs (http://www.django-rest-framework.org/api-guide/authentication/#custom-authentication). If there's any additional info needed to solve this, please let me know and I'll update. Any help on what I'm missing would be great.

To add: Just out of curiosity, do I need to make a custom authentication system if I have a custom user?

UPDATE:

I just deleted the class above, and just added the rest_framework.authentication.TokenAuthentication in my REST_FRAMEWORK settings. I'm still using a custom authentication which fetches my user.

It looks like this (not going to format it. SO sucks at formatting code from VIM):

class CustomAuthentication(object):
def authenticate(self, email=None, password=None):

    User = get_user_model()
    try:
        user = User.objects.get(email=email)
    except User.DoesNotExist:
        return None
    if user.check_password(password):
        return user

    return None

def get_user(self, user_id):
    try:
        user_model = get_user_model()
        user = user_model.objects.get(pk=user_id)
    except User.DoesNotExist:
        return None

I used this Django docs to create that code: https://docs.djangoproject.com/en/1.10/topics/auth/customizing/

回答1:

If you search for the error string in the DRF code, you find this (in authtoken/serializers.py:

from django.contrib.auth import authenticate
...

if username and password:                                                                                                                                                                                                              
    user = authenticate(username=username, password=password)                                                                                                                                                                          

    if user:                                                                                                                                                                                                                           
        # From Django 1.10 onwards the `authenticate` call simply                                                                                                                                                                      
        # returns `None` for is_active=False users.                                                                                                                                                                                    
        # (Assuming the default `ModelBackend` authentication backend.)                                                                                                                                                                
        if not user.is_active:                                                                                                                                                                                                         
            msg = _('User account is disabled.')                                                                                                                                                                                       
            raise serializers.ValidationError(msg, code='authorization')
    else:                                                                                                                                                                                                                     
        msg = _('Unable to log in with provided credentials.')                                                                                                                                                                         
        raise serializers.ValidationError(msg, code='authorization')
...

So it looks like depending on which version of Django you're using, either these credentials are incorrect, or the user is not active (for Django >= 1.10)?

Have you tried logging in manually in the admin with these credentials to verify them?



回答2:

OK I solved it. Inside my settings, I just had to remove the AUTHENTICATIONS_BACKEND. I thought my custom backend was different for merely logging a user in and the token authentication backend worked to get that token.