django-ninja
django-ninja copied to clipboard
Update request.auth instead of request.user
I was wondering why did you decide to set request.auth instead of request.user during the authentication step here:
https://github.com/vitalik/django-ninja/blob/master/ninja/operation.py#L100
When I intuitively try to access request.user I always get AnonymousUser. I mean, I always saw that other libraries set request.user, and when necessary they set some other request attributes besides user.
Is that really intended? What is the reason for that?
Thanks for your work on this library, by the way. Nice job!
Hi @ianrodrigues
Is that really intended? What is the reason for that? yes, at the moment it it intended
because for APIs your auth entity is not always a user, can be token, can be boolean, etc
if you use django-ninja as a backend for javascript client on same domain - you can use django_session auth , and then you will have request.user available as expected
but on the other hand, I will think maybe it makes sense to have request auth attribute configurable somehow...
It makes sense. However, I do believe it should have that configurable somehow, too.
In my case, django-ninja is both a backend for a React SPA (authenticating using Bearer) and a CLI tool (authenticating using Personal Access Token).
Thanks for your fast response. You can mark this issue as a question and close it.
probably implementation will be the following
class MyAuth(HttpBearer):
request_attribute = 'user' # !!!
def authenticate(self, ...):
return some_object
I solved this issue of request.user not being available by adding a call to django's login method to my Ninja auth class:
from users.models import User
from ninja.security import APIKeyHeader, django_auth
from django.contrib.auth import login
class ApiKey(APIKeyHeader):
param_name = 'X-API-Key'
def authenticate(self, request, key):
user = User.objects.filter(token__key=key).first()
if user is not None:
login(request, user, backend='django.contrib.auth.backends.ModelBackend')
return user
The token stuff is my own implementation, but basically on the user = User.objects line, you want to find the user in the database given the key that was supplied.
I hope this helps anyone else facing this situation.
I solved this issue of request.user not being available by adding a call to django's
loginmethod to my Ninja auth class:from users.models import User from ninja.security import APIKeyHeader, django_auth from django.contrib.auth import login class ApiKey(APIKeyHeader): param_name = 'X-API-Key' def authenticate(self, request, key): user = User.objects.filter(token__key=key).first() if user is not None: login(request, user, backend='django.contrib.auth.backends.ModelBackend') return userThe token stuff is my own implementation, but basically on the user = User.objects line, you want to find the user in the database given the key that was supplied.
I hope this helps anyone else facing this situation.
I don't think you need to put login(request, user, backend='django.contrib.auth.backends.ModelBackend')
Simply we can access request.user instead request.auth add this request.user = user
If you put login function there, each api call login again and again
Like @quroom said, the solution is
Simply we can access request.user instead request.auth add this request.user = user
For others:
class ApiKey(APIKeyHeader):
param_name = 'X-API-Key'
def authenticate(self, request, key):
user = User.objects.filter(token__key=key).first()
if user is not None:
request.user = user
return user
But it is a bit weird, maybe it can be documented.
Or we use request_attribute = 'user' route like @vitalik said
Using login(request, user, backend='django.contrib.auth.backends.ModelBackend') creates cookies and csrf token which we could need if we are doing an MPA (see image below)
TLDR; if you need csrf token or session use the login function from django. If you need just the user to be replaced by the .auth use request.user = user