In my Django project I have a public API endpoint built with Django Rest Framework's APIView. It does not need to know anything about the user. Still, Django automatically fetches the session and the user from the database. Is there a way to not do this since it causes two unnecessary DB hits?
Here is the code:
class TermListView(APIView):
permission_classes = ()
def get(self, request, format=None):
qs = Term.objects.all().only('original_word')
return Response([term.original_word for term in qs])
You need to add authentication_classes = () to the View class. This tells Django not to worry about the user. Or you can also configure this option globally for all your endpoints.
Related
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
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'm using DRF to allow users of my mobile app to authenticate to my web application.
I want to create a model instance associated with this user the first time a user "logs in" using the client.
I'm using token-based authentication in DRF, and for my /api/authenticate/ endpoint I'm pointing at url(r'^authenticate/', restviews.obtain_auth_token),
It seems like the best way to handle this is to override ObtainAuthToken(APIView), by adding this class to my api/views.py. This class looks like this:
class ObtainAuthTokenCustomized(APIView):
throttle_classes = ()
permission_classes = ()
parser_classes = (parsers.FormParser, parsers.MultiPartParser, parsers.JSONParser,)
renderer_classes = (renderers.JSONRenderer,)
serializer_class = AuthTokenSerializer
def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
token, created = Token.objects.get_or_create(user=user)
return Response({'token': token.key})
obtain_auth_token = ObtainAuthTokenCustomized.as_view()
It looks like I would want to insert a test prior to get_or_create for whether a token has been created previously for this user. And if so, perform the model instance creation I have planned.
Is this there a better way to handle this?
From what I can tell this is the best place to handle this.
The reason is that DRF does not currently have a token expiration capability. So once a token is created with the above class it does not go away.
This means created will return True if it is the user's first time logging in:
token, created = Token.objects.get_or_create(user=user)
Thus you'd simply test created on the following line and perform the model creation or other actions necessary.
Additional logic may be necessary to handle a situation if tokens were removed. For example, if you used created an API logout method like the one given in this answer.
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 need to create User instances through the Django Rest API. The normal Django built-in User needs to be extended, most commonly with a UserProfile model. Because of this, User objects had to be represented with a separate table for User and UserProfile in the API.
I assume I could make a single function-based view that combines serialized data from both User and UserProfile serializers, but I'm really interested to know if it's possible to do the same thing with a class-based view. It would need to have two querysets and serializer_classes, is that even possible?
You can use a simple APIView to achieve this:
from rest_framework.views import APIView
class GetProfileEmployeeView(APIView):
def get(self, request, format=None):
# I associate Django users to a matching Employee record via e-mail address
emp_profile = Employee.objects.get(email=self.request.user.email)
serializer = EmployeeSerializer(emp_profile)
return Response(serializer.data)
Then, in your urls.py add an endpoint that points to this view:
urlpatterns = [
url(r'^profile/?$', utility_views.GetProfileEmployeeView.as_view()),
]
When users GET that endpoint they'll get back their entire user profile. You can also go crazy and manually craft a response that's composed of data from multiple model objects:
def get(self, request, format=None):
employee = Employee.objects.get(id=self.request.employee.id)
company = toolbox.get_employee_company(employee)
profile_co = CompanySerializer(company).data
profile_co['licenses'] = AccountSerializer(Account.objects.get(company=company)).data['license_count']
profile = {}
profile['id'] = employee.id
profile['first_name'] = employee.first_name
profile['last_name'] = employee.last_name
profile['email'] = employee.email
profile['is_admin'] = employee.is_admin
profile['company'] = profile_co
return Response(profile)