3

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/

rocky raccoon
  • 514
  • 1
  • 8
  • 23
  • Just to answer your curiosity: No, you do not need a custom Authentication if you are using a custom user. The build I use at work has a custom user and uses the default ModelBackend shipped with Django. :) – gallen Feb 24 '17 at 02:20
  • @Neelik ayyyee hook me up with a job there! – rocky raccoon Feb 24 '17 at 02:34
  • Maybe when the company grows a bit :P We're still a little local group right now. – gallen Feb 24 '17 at 02:44
  • The indentation in your code (the `try:) line, is incorrect, but I suspect this is only in this question, not in your actual code? – Laurent S Feb 24 '17 at 03:32
  • Yes, it's just in the question. Copying and pasting from vim is sort of a pain. – rocky raccoon Feb 24 '17 at 03:42

2 Answers2

2

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?

Laurent S
  • 4,106
  • 3
  • 26
  • 50
  • I'm doing iOS development and using the email and password to log in which is fine. I went to the shell, and queried for the user's username and it's correct. I just checked if the user is active, and it shows 'true'. Does everything look correct in my question, or am I just missing something I'm not aware of? – rocky raccoon Feb 24 '17 at 03:43
  • btw, yes I'm using Django 1.10.2 – rocky raccoon Feb 24 '17 at 03:44
1

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.

rocky raccoon
  • 514
  • 1
  • 8
  • 23