I have a following user view:
class UserViewSet(viewsets.ModelViewSet):
serializer_class = UserSerializer
permission_classes = [NotSafeMethodAndAllowAny | permissions.IsAuthenticated]
def get_queryset(self):
if self.request.user.is_superuser:
return User.objects.all()
else:
return User.objects.filter(id=self.request.user.id)
#action(detail=False, methods=["get"])
def current(self, request, *args, **kwargs):
return Response(self.get_serializer(request.user).data)
As this is a ModelViewSet, it allows API users to create, list, update, delete the users.
Don't mind the NotSafeMethodAndAllowAny permission.
Now I want to somehow protect my API from the users using it like in a script. For example, when I submit the user registration form on my frontend (a separate React app), it should be accepted, but if someone posts to my api/user/ with random registration data like from Postman/curl/etc., I want it to be discarded.
Is there a way for DRF to distinguish between those two types of requests? And possibly via some setting, so I can test it via Postman when in development, but when it runs in production, it would not accept automated requests. I want to prevent a situation where someone would create like a bazillion users in a matter of minutes.
BTW: I use JWT for authentication, but for obvious reasons the registration/login endpoints do not require authentication.
If i understand maybe you can create a CustomPermission and only allow requests from specific IP ADDRESS.
from rest_framework import permissions
class IpAddressPermission(permissions.BasePermission):
"""
Global permission check for IPs.
"""
def has_permission(self, request, view):
remote_address = request.META['REMOTE_ADDR']
if remote_addr == settings.ALLOWED_IP_ADDRESS:
return True
return False
Related
My question address to the usage of Django permission architecture even when the front is on Vue.js and data is requested/responded through Django REST framework.
I am a little confused about being able to use default permission libraries of Django when the app is combined with Rest Framework and VueJs:
from django.contrib.auth.decorators import login_required, permission_required
#permission_required('pobapp.can_add_instance')
#login_required
def addEmployeeInstance(request):
return render(request, 'pobapp/search.html')
If not, how can I restrict some data and pages for specific users? For example, if I only wanted to let authenticated users to view some specific pages?
If you want to restrict a logged user in pages, first, you should define a Role and a Resource model for User model.
Then, you can define a permission class for controlling this restriction. for example my permission class for this purpose is like this,
class IsAuthRolePermission(permissions.BasePermission):
def has_permission(self, request, view):
if request.user.is_authenticated:
try:
obj = Resource.objects.get(name=view.__class__.__name__,
roles__in=request.user.roles.all())
return True
except Resource.DoesNotExist:
return False
else:
return False
I am building a Restapi using Django and Rest framework and mongoengine, so far all requests require a user to be authenticated and check against a token.
But now I need to allow different actions to different users. I don't know where to begin. Any guidelines ?
For example I want only the admin to be able to write and read users objects:
class UsersViewSet(ModelViewSet):
queryset = Users.objects.all()
serializer_class = UsersSerializer
def me(self, request, *args, **kwargs):
serializer = self.serializer_class(request.user)
return Response(serializer.data)
Read the chapter on custom permisssion. You will want to extend permissions.BasePermission and provide the authentication logic inside has_permission.
from rest_framework import permissions
class CustomUserPermission(permissions.BasePermission):
def has_permission(self, request, view):
# return True if user has permission
pass
Then inside your view.
class UsersViewSet(ModelViewSet):
permission_classes = (CustomUserPermission,)
I have following functions in rest API for User model. I want to set AllowAny permission on only POST request. Can someone help me out.
class UserList(APIView):
"""Get and post users data."""
def get(self, request, format=None):
"""Get users."""
users = User.objects.all()
serialized_users = UserSerializer(users, many=True)
return Response(serialized_users.data)
def post(self, request, format=None):
"""Post users."""
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
You can write a custom Permission class IsPostOrIsAuthenticated which will allow unrestricted access to POST requests but will allow only authenticated GET requests.
To implement the custom permission IsPostOrIsAuthenticated, override the BasePermission class and implement .has_permission(self, request, view) method. The method should return True if the request should be granted access, and False otherwise.
from rest_framework import permissions
class IsPostOrIsAuthenticated(permissions.BasePermission):
def has_permission(self, request, view):
# allow all POST requests
if request.method == 'POST':
return True
# Otherwise, only allow authenticated requests
# Post Django 1.10, 'is_authenticated' is a read-only attribute
return request.user and request.user.is_authenticated
So, all POST requests will be granted unrestricted access. For other requests, authentication will be required.
Now, you need to include this custom permission class in your global settings.
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'my_app.permissions.IsPostOrIsAuthenticated',
)
}
http://www.django-rest-framework.org/api-guide/permissions/
as per above URL you have to write one custom permission class
class ExampleView(APIView):
permission_classes = (MyCustomAuthenticated,)
Write your own logic using AllowAny or IsAuthenticated inside MyCUstomAuthenticated based on POST and GET
I am trying to implement TokenAuthentication using the Rest Framework, but it seems that I can't add my own custom decorators to my ViewSets because they are evaluated BEFORE the authentication. Consider this:
from django.utils.decorators import method_decorator
from django.http.response import HttpResponseForbidden
def require_staff(View):
def staffOnly(function):
def wrap(request, *args, **kwargs):
if request.user.is_active and request.user.is_staff:
return function(request, *args, **kwargs)
else:
return HttpResponseForbidden()
return wrap
View.dispatch = method_decorator(staffOnly)(View.dispatch)
return View
When I try to implement this, it seems the decorator code fires first, so the authentication is never run.
#require_staff
class CustomerViewSet(ModelViewSet):
model = Customer
filter_class = CustomerFilter
filter_backends = (DjangoFilterBackend,)
Since request.user is never set, introducing the decorator breaks authentication.
I think the issue is that Authentication is occuring the rest_frameworks dispatch() function and it is not clear to me how I could add additional (say) custom security if authentication is done that late in the game.
Am I missing something here, or what is the proper way to implement this customization?
Someone suggested using Permissions for this instead. I assume they mean custom DRF Permissions, right?
Everything you need to know is DRF permissions is here: http://www.django-rest-framework.org/api-guide/permissions
DRF provides a built in permission that is similar to yours, called IsAdminUser
The IsAdminUser permission class will deny permission to any user,
unless user.is_staff is True in which case permission will be allowed.
This permission is suitable is you want your API to only be accessible
to a subset of trusted administrators.
To use this permission in a Class Based View:
class ExampleView(APIView):
permission_classes = (IsAdminUser,)
Now you have two options to do an extra check for user.is_active.
The first is override the IsAdminUser permission, like so:
from rest_framework import permissions
class IsActiveAndAdminUser(permissions.IsAdminUser):
"""Only allow a user who is Admin and Active to view this endpoint. """
def has_permission(self, request, view):
is_admin = super(IsAdminAndActiveUser, self).has_permission(request, view)
return request.user.is_active and is_admin
The second is to create an IsActiveUser permission, and chain them in your view.
IsActiveUser Permission:
from rest_framework import permissions
class IsActiveUser(permissions.BasePermission):
""" Only Active Users have permission """
def has_permission(self, request, view):
return request.user.is_active
Your new permission list in your class based view:
class ExampleView(APIView):
permission_classes = (IsActiveUser, IsAdminUser,)
I have the following ModelViewSet
class UserViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
queryset = User.objects.all()
serializer_class = UserSerializer
authentication_classes = (TokenAuthentication,)
permission_classes = (permissions.IsAuthenticated, MyUserPermissions)
I want the create method (POST on /users/) to not ask for any authentication. How can I override the authentication_classes in this case? I'm talking about ModelViewSet not generic API views.
I want the create method (POST on /users/) to not ask for any authentication.
Actually that's not quite what you want. You want POST on users to not require any permissions, which will have the effect that either authenticated or unauthenticated requests will succeed.
I'd suggest overriding your permission classes so that they always allow POST requests. Follow the custom permissions documentation for more info on that.
Essentially you'll have something like:
class IsAuthenticatedOrCreate(permissions.IsAuthenticated):
def has_permission(self, request, view):
if request.method == 'POST':
return True
return super(IsAuthenticatedOrCreate, self).has_permission(request, view)
And probably something similar for your other permission class too.