I'm writing api using django rest framework using Token Authentication method written as below
#api_view(['GET'])
#permission_classes((IsAuthenticated, ))
def ah(request, format=None):
result = request.user.is_authenticated()
content = {"hello":result}
return Response(content)
my settings are
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAdminUser',
'rest_framework.permissions.IsAuthenticated',
],
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
#'rest_framework.authentication.BasicAuthentication',
#'rest_framework.authentication.SessionAuthentication'
)
}
MIDDLEWARE_CLASSES = [
'django.contrib.sessions.middleware.SessionMiddleware',
#'middleware.FirstTokenAuth.AuthenticationMiddlewareJWT',
#'middleware.TokenAuthTest.JWTAuthenticationMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.middleware.security.SecurityMiddleware',
#'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
#'django.middleware.csrf.CsrfViewMiddleware',
#'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
When I call this API using IsAdminUserpermission class The django restframework returns:
403 response "detail": "Authentication credentials were not provided." if the token wasn't provided in the header
401 response "detail": "You do not have permission to perform this action."
if the token was not for admin user
but the main problem is here when I set
#permission_classes((IsAuthenticated, ))
The API is called normally without returning 403 or 401 even if i didn't add a token to the header and the user returned is anonymous user.
How can I prevent anonymous user from calling API and return 403 response for him.
Any help Please !!
The #permission_classes is for identifying if the api needs authentication. If you want to use token, try to add #authentication_classes with TokenAuthentication inside. This will check the token in your header and create the user object inside request.
Use this:
permission_classes = [permissions.IsAuthenticated,]
It worked for me.
Related
I have hosted a website at http://cognezic-dev.ap-south-1.elasticbeanstalk.com/login/. On closer inspection, the form has the same csrf token across page refreshes and browsers, which I suspect to be the cause of the issue,this works fine on the local django server.Dont know where this is being cached. I have added CSRF Middleware in the settings.py too.
You can use the test credentials as username bismeet and password bis12345 for testing.
I have also tried creating a custom middleware as follows:
from django.middleware.csrf import rotate_token, CsrfViewMiddleware
from django.utils.deprecation import MiddlewareMixin
class CSRFRefresh(CsrfViewMiddleware,MiddlewareMixin):
def process_response(self, request, response):
print("Custom MiddleWare called")
rotate_token(request)
return response
But it still fails.
My settings.py with custom middleware contains:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'solvesto.middleware.csrf_refresh.CSRFRefresh'
]
If not using the custom middleware,I use:
'django.middleware.csrf.CsrfViewMiddleware'
instead of
'solvesto.middleware.csrf_refresh.CSRFRefresh'
The only last resort I see to make this work is to remove csrf altogether,which is of course,bad for security.
I removed the csrf security,no other solution,works now.
I try to add the business attribute to the request object by using my own middleware, it nicely works with rest_framework.authentication.SessionAuthentication and I can use request.business in my views. But when I try to authenticate with JWT method (rest_framework_simplejwt.authentication.JWTAuthentication) when my middleware code is run request.user is set to AnonymouseUser so can't fetch business associated with user? Why did this happen?
# middleware.py
class MyMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
request.business = None
if request.user.is_authenticated and hasattr(request.user, 'business'):
request.business = request.user.business
response = self.get_response(request)
return response
Middlewares:
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'my_app.middleware.MyMiddleware',
]
rest_framework settings:
REST_FRAMEWORK = {
...
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
'rest_framework.authentication.SessionAuthentication',
],
}
Unfortunately, DEFAULT_AUTHENTICATION_CLASSES are not processed in middleware process, but in the view itself. What is giving you the proper user when using session is the Django's AuthenticationMiddleware and REST Framework is just using this value when the session authentication is enabled.
To solve that, you can do one of the following:
Move adding request.business to the views (for example by adding some class that all your views will inherit from)
Move JWT authentication into Django middlewares (this has a side effect of DRF enforcing CSRF checks by default when user is logged in)
I'm working with both the latest Django 3.0.2 and DRF 3.11.0 using djangorestframework-simplejwt 4.4.0. I did not have this problem before on a previous Django 2.2.0 project (and older lib versions), but I cannot figure out why I cannot access a view with readonly permissions set and default authentication looks okay in settings. For the simplejwt and firebaseauth library, I'm using the default settings (with correct credentials for firebaseauth, verified it works fine).
If I specify the authentication_classes as empty in the view, then it works fine, but this is just an example. I expected the defaults to work, from settings: unless I'm incorrect and should be explicitly set this way. I have also tried using gunicorn and waitress-serve, and it's the same result.
Here is the view:
class NoteList(generics.ListAPIView):
"""
List all Notes. Not used
"""
# authentication_classes = []
permission_classes = (permissions.AllowAny,)
serializer_class = NoteSerializer
def get_queryset(self):
notes = Note.objects.all()
return notes
Here is my settings:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
REST_FRAMEWORK = {
# When you enable API versioning, the request.version attribute will contain a string
# that corresponds to the version requested in the incoming client request.
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.NamespaceVersioning',
# Authentication settings
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
'rest_framework.authentication.SessionAuthentication',
'drf_firebase_auth.authentication.FirebaseAuthentication',
],
# Permission settings
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',
'rest_framework.permissions.IsAuthenticated',
'rest_framework.permissions.IsAdminUser',
'rest_framework.permissions.IsAuthenticatedOrReadOnly',
],
# For unit test cases
'TEST_REQUEST_DEFAULT_FORMAT': 'json',
# Pagination
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 50,
}
If ordering the above matters, what is the correct order to have them in?
Urls, if it matters:
urlpatterns = [
path('anotes/', NoteList.as_view(), name="lame-notes"),
]
Now, when I visit the URL anonymously, I always get:
GET /v1/anotes/
HTTP 401 Unauthorized
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
WWW-Authenticate: Bearer realm="api"
{
"detail": "Invalid Authorization header format, expecting: JWT <token>."
I've been stuck on this issue for a while and could not find any similar problems to solve it. On my older Django project, I don't get this 401 Unauthorized and am able to have ReadOnly work correctly.
The view or endpoint only works correctly if I'm logged in.
If I'm missing any information please let me know.
Permissions in REST framework are always defined as a list of permission classes.
Before running the main body of the view each permission in the list is checked. If any permission check fails an exceptions.PermissionDenied or exceptions.NotAuthenticated exception will be raised, and the main body of the view will not run.
So an anonymous user can check the first item in your permission list, but fails at second. You should decide what will your default behavior will be and keep that in the list.
My settings.py:
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.RemoteUserBackend',
'django.contrib.auth.backends.ModelBackend',
]
MIDDLEWARE = [
# ...
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.RemoteUserMiddleware',
# ...
]
ModelBackend is used by the DRF Browsable API.
RemoteUserBackend is used by the frontend app.
If a user logs into the Browsable API, the frontend will send both the auth token and the session token. Both credentials are diferent django users.
AUTHENTICATION_BACKENDS are suposed to work by order, but AuthenticationMiddleware goes first in MIDDLEWARE , it's mandatory.
A session-authenticated user gets wrong data in the frontend app. Django ignores remote user credentials. The user must logout from the browsable API.
How can I fix this?
Just for the record. I simply did a logout from the frontend at page load.
I am trying to use oauth for authentication and authorization in a project. I want to use the client credentials grant type as this project is about a middleware/api that will be consumed by a client application. I have created one corresponding client_id and client_secret. The token generation is working, however as soon as I am trying to do a request with the generated token against the api endpoint i am being forwarded to the accounts/login page by django:
<td>http://127.0.0.1:8000/accounts/login/?next=/api/mp/</td>
my settings are:
MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
'oauth2_provider.middleware.OAuth2TokenMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',]
AUTHENTICATION_BACKENDS = (
'oauth2_provider.backends.OAuth2Backend',)
And this the top of my only function in my views:
#csrf_exempt
#require_http_methods(['POST', 'GET'])
#login_required()
def getUserContext(request):
I am not really understanding where this additional authentication is coming from or resp. how i can tell django to only use oauth for the view.
Found the answer very short after posting the questions. However, had been following a howto that stated #login_required to be used. However, the correct decortator to be used is:
#protected_resource()