Search code examples
pythondjangotastypie

How can I login to django using tastypie


I'm trying to override is_authenticated in my custom authentication. I have something simple (to start with) like this:

class MyAuthentication(BasicAuthentication):
    def __init__(self, *args, **kwargs):
        super(MyAuthentication, self).__init__(*args, **kwargs)

    def is_authenticated(self, request, **kwargs):
        return True

then in my ModelResource I have

class LoginUserResource(ModelResource):

    class Meta:
        resource_name = 'login'
        queryset = User.objects.all()
        excludes = ['id', 'email', 'password', 'is_staff', 'is_superuser']
        list_allowed_methods = ['post']

        authentication = MyAuthentication()
        authorization = DjangoAuthorization()

I keep getting a 500 error back with "error_message": "column username is not unique". I only have one username in the db and it's the user I am trying to authenticate.

Any ideas as to why it's returning this error? How would I allow an api client to login?

Thanks for the help.


Solution

  • Your approach will try to create a new user with the username that you are authenticating with. This will bubble up at the DB layer, as you've noticed, that such a user already exists.

    What you want is to create a UserResource, add a method on it that users can post to and login with data passing in username/password.

    from django.contrib.auth.models import User
    from django.contrib.auth import authenticate, login, logout
    from tastypie.http import HttpUnauthorized, HttpForbidden
    from django.conf.urls import url
    from tastypie.utils import trailing_slash
    
    class UserResource(ModelResource):
        class Meta:
            queryset = User.objects.all()
            fields = ['first_name', 'last_name', 'email']
            allowed_methods = ['get', 'post']
            resource_name = 'user'
    
        def override_urls(self):
            return [
                url(r"^(?P<resource_name>%s)/login%s$" %
                    (self._meta.resource_name, trailing_slash()),
                    self.wrap_view('login'), name="api_login"),
                url(r'^(?P<resource_name>%s)/logout%s$' %
                    (self._meta.resource_name, trailing_slash()),
                    self.wrap_view('logout'), name='api_logout'),
            ]
    
        def login(self, request, **kwargs):
            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', '')
    
            user = authenticate(username=username, password=password)
            if user:
                if user.is_active:
                    login(request, user)
                    return self.create_response(request, {
                        'success': True
                    })
                else:
                    return self.create_response(request, {
                        'success': False,
                        'reason': 'disabled',
                        }, HttpForbidden )
            else:
                return self.create_response(request, {
                    'success': False,
                    'reason': 'incorrect',
                    }, HttpUnauthorized )
    
        def logout(self, request, **kwargs):
            self.method_check(request, allowed=['get'])
            if request.user and request.user.is_authenticated():
                logout(request)
                return self.create_response(request, { 'success': True })
            else:
                return self.create_response(request, { 'success': False }, HttpUnauthorized)
    

    Now you can do send a POST to http://hostname/api/user/login with data { 'username' : 'me', 'password' : 'l33t' }.