Im using DRF to build my backend endpoint.
I have a viewset protected by isAuthenticated permission_class.
class SubnetViewSet(viewsets.ViewSet):
permission_classes = [IsAuthenticated]
Every endpoint requires autnetication and it works perfectly.
Unfortunally, one endpoint of this viewset must be accessible without authentication.
#action(detail=False, methods=['get'])
def endpoint_free(self, request):
[...]
Is there a way to exclude only this endpoint without create a new ViewSet. I have found nothing on official Docs.
Thanks.
Just pass in permission_classes argument:
#action(detail=False, methods=['get'], permission_classes=[permissions.AllowAny])
def endpoint_free(self, request):
...
Related
The below is an api that required authen. It works
class some_random_api(generics.GenericAPIView):
permission_classes = (IsAuthenticated, )
def get(self,request):
return HttpResponse("Called successfully")
However, I dont like declaring variable. After looking up this document, https://www.django-rest-framework.org/api-guide/permissions/ . I find an alternative way by using decorator. So I change my code into this.
from rest_framework.decorators import permission_classes
class some_random_api(generics.GenericAPIView):
#permission_classes(IsAuthenticated)
def get(self,request):
return HttpResponse("You call random test api")
Now this API does not check Authen
The decorator #permission_classes is only applicable to function-based API views as documented.
REST framework provides a set of additional decorators which can be added to your views. These must come after (below) the #api_view decorator.
The available decorators are:
...
#permission_classes(...)
...
Also here:
Or, if you're using the #api_view decorator with function based views.
#api_view(['GET'])
#permission_classes([IsAuthenticated])
def example_view(request, format=None):
...
An alternative to defining a fixed list permission_classes = (IsAuthenticated, ) is to override the get_permissions() and assign different permissions for the different HTTP methods as described here.
class some_random_api(generics.GenericAPIView):
def get_permissions(self):
if self.request.method == "GET": # If using viewsets, the self.action can be used e.g. <if self.action == "retrieve":>
permission_classes = [permissions.IsAuthenticated]
else:
permission_classes = [permissions.IsAdminUser]
return [permission() for permission in permission_classes]
def get(self, request):
return HttpResponse("You call random test api")
Related questions:
Django Rest Framework - GenericViewSet with Authentication/Permission decorator
Django REST Framework - Separate permissions per methods
i am using keycloak as IAM for my project which is a multi service project.
i want to use django rest framework for my django service.
i have managed to make authentication work and request.user returns an instance of User from django.contrib.auth.models, the problem is drf creates a new request object for the view, and the user authenticated by keycloak backend set in AUTHENTICATION_BACKENDS is lost,
to solve this problem i have made a permission class like the following:
class ClientRoleBasedPermission(permissions.BasePermission):
role = "create_room"
def has_permission(self, request, view):
if self.role in request._request.user.get_all_permissions():
return True
return False
i am using this simple view to test things
class ListUsers(APIView):
"""
View to list all users in the system.
* Requires token authentication.
* Only admin users are able to access this view.
"""
permission_classes = [CreateRoomPermission]
permission = "create_room"
def get(self, request, format=None):
"""
Return a list of all users.
"""
usernames = [user.username for user in User.objects.all()]
return Response(usernames)
authentication backend i am using :KeycloakAuthorizationCodeBackend
is there a better way to solve this issue ?
I am trying to build a system in Django without using any of its batteries -- auth, admin etc. The system uses the Django rest framework for the API.
However, when I try to request to an API, I keep getting this error:
Model class django.contrib.auth.models.Permission doesn't declare an explicit
app_label and isn't in an application in INSTALLED_APPS.
I do not want to use django.contrib.auth at all. I did the following inside my DRF API View class:
class NewsPostView(APIView):
permission_classes = None
def get(self, request, format=None):
posts = NewsPost.objects.all()
serializer = NewsPostSerializer(posts, many=True)
return Response([])
However, I am still getting the same error. How can I disable auth from DRF?
I have solved my issue. After #Linovia's response, I checked the docs etc of DRF and changed the following properties:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [],
'DEFAULT_PERMISSION_CLASSES': [],
'UNAUTHENTICATED_USER': None,
}
And everything worked.
Use AllowAny instead of None. And also your response seems to be returning empty list. use serializer.data for retrieving data
from rest_framework.permissions import AllowAny
class NewsPostView(APIView):
permission_classes = (AllowAny,)
def get(self, request, format=None):
posts = NewsPost.objects.all()
serializer = NewsPostSerializer(posts, many=True)
return Response(data=serializer.data)
Make sure you don't use rest_framework.urls and that your settings has:
'DEFAULT_AUTHENTICATION_CLASSES': tuple(),
as well as your views.
With some luck, you won't have the authentication imported through another import.
I want to add some REST API views to an existing Django project, which uses vanilla Django views. For that I'd like to use the REST Framework. I wonder if I can I mix Django and RF views in a single project and what pitfalls this might have (e.g. with authentication).
Yes you can surely use both of them at the same time, there shouldn't be any issue. Typically the Django views use SessionAuthentication, adn you will use DRF using TokenAuthentication -- best practice is to add both Session and Token authentication to the authentication_classes in the DRF views - that way you can use the browsable api pages to browse the apis once you have signed in via password (session authentication) as well
class GenericViewTest(SuperuserRequiredMixin, View):
def get(self, request, *args, **kwargs):
return HttpResponse("Test")
class PostTrackingCode(CreateAPIView):
"""
"""
authentication_classes = (SessionAuthentication, TokenAuthentication) ----> note this
permission_classes = (permissions.IsAuthenticated,)
serializer_class = TrackingInfoWriteSerializer
model = TrackingInfo
I understand that we can set up authentication classes in class based viewsets like this:
class ExampleViewSet(ModelViewSet):
authentication_classes = (SessionAuthentication, BasicAuthentication)
However, is there a way to dynamically change the authentication class based on the request method? I tried overriding this function in my ExampleViewSet:
def get_authenticators(self): # Found in
if self.request.method == "POST":
authentication_classes.append(authentication.MyCustomAuthentication)
return authentication_classes
However, django rest does not have the request object setup at this point:
'ExampleViewSet' object has no attribute 'request'
Note: not real variable names - just for example purpose.
Based on the previous answer, it works on django 1.10
#detail_route(methods=['post', 'get'])
def get_authenticators(self):
if self.request.method == "GET":
self.authentication_classes = [CustomAuthenticationClass]
return [auth() for auth in self.authentication_classes]
You can use detail_route decorator from rest_framework like this for getting requests,
detail_route can be used to define post as well as get,options or delete options
So,the updated code should be like :
from rest_framework.decorators import detail_route
class ExampleViewSet(ModelViewSet):
authentication_classes = (SessionAuthentication, BasicAuthentication)
#detail_route(methods=['post','get'])
def get_authenticators(self, request, **kwargs): # Found in
if request.method == "POST":
authentication_classes.append(authentication.MyCustomAuthentication)
return authentication_classes
For further reading,Read from here.