Tastypie : Authentication for GET and Anonymous for POST

后端 未结 2 1157
广开言路
广开言路 2021-02-14 07:21

I use Django/Tastypie to manage my user collection.

Is it possible to allow anonymous users to POST in the API (when creating a new user at some endpoint) and restrict a

相关标签:
2条回答
  • 2021-02-14 08:01

    Yes, it's possible to do both.

    Here's a simple example of how you would let an authenticated user GET only their own user JSON and not from all the other users: (Assuming you are using Django's built-in user infrastructure):

    # In api.py (or resource.py):
    ...
    from tastypie.resources import ModelResource
    from tastypie import fields
    from models import *
    from django.contrib.auth.models import User, Group
    from tastypie.authentication import BasicAuthentication
    from tastypie.authorization import DjangoAuthorization
    ...
    
    # REST endpoint for authenticating user accounts
    class UserResource(ModelResource):
    
        class Meta:
            queryset = User.objects.all()
            resource_name = 'auth/user'
            list_allowed_methods = ['get']
            detail_allowed_methods = ['get']
            authentication = BasicAuthentication()
            authorization = DjangoAuthorization()
    
        def apply_authorization_limits(self, request, object_list):
            return object_list.filter(username=request.user)
    

    And here is a simple example of how you would let an anonymous user POST to create a new user (Caveat: this doesn't use Tastypie, strictly speaking)

    # In views.py:
    ...
    from django.http import HttpResponse
    from django.contrib.auth.models import User, Group
    from django.contrib.auth import authenticate
    from django.http import Http404
    from django.utils import timezone
    from models import *
    from api import *
    from django.utils import simplejson
    ...
    
    # REST endpoint for user registration
    # Enforces server-side mediation (input validation)
    # On failure, raises Http404
    # On success, redirects to registration success page
    def register_user(request):
        if request.method != 'POST':
            raise Http404('Only POSTs are allowed')
    
        # acquire params
        username = request.POST['username']
        password = request.POST['password']
        repeatpw = request.POST['repeatpw']
        first_name = request.POST['first_name']
        last_name = request.POST['last_name']
    
        # Server-side mediation to check for invalid input
        if username == '' or username is None:
            raise Http404('Server-side mediation: Invalid Username')
    
        if len(username) > 30:
            raise Http404('Server-side mediation: username must be 30 characters or fewer')
    
        if len(first_name) > 30:
            raise Http404('Server-side mediation: first name must be 30 characters or fewer')
    
        if len(last_name) > 30:
            raise Http404('Server-side mediation: last name msut be 30 characters or fewer')
    
        if len(password) < 4:
            raise Http404('Server-side mediation: Password too short')
    
        if password != repeatpw:
            raise Http404('Server-side mediation: Password Mismatch')
    
        # This try-except block checks existence of username conflict
        try:
            test_user_exists = User.objects.get(username__exact=username)
            if test_user_exists != None:
                raise Http404('Server-side mediation: Username exists')
        except User.DoesNotExist:
            pass
    
        # Input passes all tests, proceed with user creation
        user = User.objects.create_user(username, 'default@nomail.com', password)
        group = Group.objects.get(name='Standard')
        user.first_name = first_name
        user.last_name = last_name
        user.groups.add(group)
        user.is_staff = False    
        user.save()
    
        # Build confirmation JSON
        confirmation = {
                'action': 'register_user',
                'username': username,
                'success': 'yes',
        }
    
        json_return = simplejson.dumps(confirmation)
    
        # return JSON of the success confirmation
        return HttpResponse(json_return, mimetype='application/json')
    

    Based on that, here's a script of how you might create a new user through the REST endpoint using curl:

    #!/bin/bash
    echo "Usage: ./register_user username password repeatpw first_name last_name"
    curl -v -d "username=$1&password=$2&repeatpw=$3&first_name=$4&last_name=$5" http://127.0.0.1:8000/register_user/ > result
    
    0 讨论(0)
  • 2021-02-14 08:08

    I found the easiest thing to do was subclass the Authentication class I'm using. Just override the is_authenticated method to return True when the method is POST.

    class AnonymousPostAuthentication(BasicAuthentication):
        """ No auth on post / for user creation """
    
        def is_authenticated(self, request, **kwargs):
            """ If POST, don't check auth, otherwise fall back to parent """
    
            if request.method == "POST":
                return True
            else:
                return super(AnonymousPostAuthentication, self).is_authenticated(request, **kwargs)
    

    I put my validation in a subclass of Validation and override is_valid.

    I do the GET filtering the same way Sampson does it above.

    0 讨论(0)
提交回复
热议问题