I'm trying to create a custom authentication class in the Django rest framework. In the authenticate(self, request) method, at first glance, it seems that there is no way to get named kwarg from the URL. Is there a way to accomplish this?
You can get url via request.get_full_path():
def authenticate(self, request):
...
url = request.get_full_path()
Check django docs in https://docs.djangoproject.com/en/3.2/topics/auth/customizing/#writing-an-authentication-backend you might find it useful
Related
I can secure the index view by having my own CustomeIndexView and check whether is authenticated there. But this won't secure a model view, for example, the URL /admin/MyModel/ is still not secured. Is there a way to secure the whole site, basically any url like /admin/xxx/?
one way to do this is by customizing is_accessible in ModelView. But i still feel it's more straight-forward if it can be done by limiting access by the root url
By the way, i'm using flask-login
You can inherit from ModelView:
class LoginRequiredView(ModelView):
def is_accessible(self):
return current_user.is_authenticated
def inaccessible_callback(self, name, **kwargs):
return redirect(url_for('admin.login', next=request.url))
Then use this view instead of ModelView to add your model:
admin.add_view(LoginRequiredView(User, db.session))
You can use before_request to check if current_user.is_authenticated and return 401 response if not, as in:
#app.before_request
def before_request():
if request.full_path.startswith('/admin/'):
if not current_user.is_authenticated:
abort(401, 'Please log in')
You can also use this to redirect to login page, for example.
I am using Django Rest Framework and I've included a 3rd party package called REST framework simple JWT Auth which is the new framework referenced,
and this one, REST framework JWT Auth, which is the old one (I Imagine), since there was no update on github since a long time and maybe not supported for newer versions.
And I'm looking for a way, like this link on stackoverflow-3rd answer, via middlewares, to get the user information for each request in order to apply/save it, in needed, the user object in my models by using django signals.
I checked in documentation and on internet, but I didn't find anything. So, if you already had that case, I will appreciate your help.
Thank you
To get username from the user model you should use request.user. This will give you the authenticated user's info with the request. However if you use simple_jwt, it's not possible to directly use request.user in a middleware because authentication mechanism works in view function.
So you should manually authenticate inside the middleware and then you can use request.user to get whatever data from the user model.
from rest_framework_simplejwt import authentication
class MyMiddleware():
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
return response
def process_view(self, request, view_func, view_args, view_kwargs):
request.user = authentication.JWTAuthentication().authenticate(request)[0] # Manually authenticate the token
print(request.user) # Use the request.user as you want
With simple_jwt the user information will not be set on the request initially but after the request is processed it will be. So if you're just logging the information and you can do it after the request is processed, do it there.
So for example in a simple middleware:
def simple_middleware(get_response):
def middleware(request):
# request.user is an anonymous user at this point
response = get_response(request)
# request.uesr is the logged-in user here
return response
return middleware
I have a model, called rides, which I want to have access to my custom token authentication. I do not want this to be a made public to the whole viewset.
How can I add the authentication method to the create method? The below throws an error complaining I can't add a list_route to a create method as it exists already.
class RideViewSet(viewsets.ModelViewSet):
# POST /rides/
#list_route(methods=['post'], authentication_classes=[CustomTokenAuth])
def create(self, request, *args, **kwargs):
The decorator won't work on the ViewSet's list / create / ...
You'll need to deal with the authenticate by yourself.
Therefore you need to fill the DRF's request with:
request._authenticator as the auth backend that has been doing the auth
request.user, request.auth as the result of your auth backend's authenticate()
I would like to get kwargs in Tastypie custom authorization. I've to authorize whether user has access to the id in URL kwargs.
Authorization methods doesn't seem to pass kwargs but passes only bundle and object_list.
As you said, a custom Authorization does not has **kwargs in the signature.
But you can access URL parameters (like id) using bundle.request.
This kind of example bellow should work:
class RestrictedIdAuthorization(Authorization):
def read_detail(self, object_list, bundle):
param_id = bundle.request.GET['id']
accepted_ids = [42, 54, 67] # Must be changed, of course.
return param_id in accepted_ids
You can take a look to this post to have another example.
I am switching to the class-based views. I also use JavaScript to confirm any deletion on the client side. Django DeleteView requires a delete confirmation template which I don't care about.
Is there any simple way of disabling the confirmation on any kind of deletes in Django?
class EntryDeleteView(DeleteView):
model = Entry
success_url = reverse_lazy('entry_list') # go back to the list on successful del
template_name = 'profiles/entry_list.html' # go back to the list on successful del
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(EntryDeleteView, self).dispatch(*args, **kwargs)
You should make a POST query from clientside (with AJAX or POSTing a form). That's because if you'll allow to delete something by GET, your service will be vulnerable to CSRF. Someone will send your admin a in email or somehow else, and you'll be in trouble.
The DeleteView renders the confirmation page on GET and deletes the object if you use a POST or DELETE. If your JS does a POST to the url after confirmation it should work like you want.