Django Authentication process - django

I noticed that when I logged in as administrator, I don't need to reauthenticate when I access non-admin area.
However, when I login as simple user and access admin zone, Django, of course, checks whether I am admin.
Where this check occurs? I want to restrict access of moderators to non-admin part of site, so need to check that.
Thank you.

Use the #user_passes_test decorator:
from django.contrib.auth.decorators import user_passes_test
def not_staff_user(user):
return not user.is_staff
#user_passes_test(not_staff_user)
def my_view(request):
...
If you want to restrict ALL pages except /admin/ then middleware is a good option:
from django.conf import settings
from django.shortcuts import redirect
class NonStaffMiddleware(object):
def process_request(self, request):
if request.user.is_staff and not \
(request.path.startswith('/admin/') or
request.path.startswith(settings.LOGIN_URL) or
request.path.startswith(settings.LOGOUT_URL)):
return redirect(settings.LOGIN_URL)

You have the user.is_staff, user.is_superuser and user.is_authenticated functions to check this wether in your views or templates. If you need to do this in your templates, the user is in the {{ request.user }} and also in your views with request.user.

Related

Restrict unauthorised access in Django

I have various applications in a Django project, but I only want users who are logged in to be able to access those pages. How can I restrict access to every pages except the login page which is my main page. For instance, mywebsite.com/home/user should be only available to user and if someone types in that it should redirect them to mywebsite.com
Currently I have two apps, main and Home, I am using ClassBased views on my Home app how can I restrict access to all my pages except login page and show a message as well?
I want to create a template that users can see other user profile details but not change or edit them. How can I do those above steps
Thanks in advance!
According to Docs you can decorate the class based views with #login_required
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
#method_decorator(login_required, name='dispatch')
class ClassBasedView(View):
...
...
Since you are using class based view, you need to add method decorator, else you can use #logine_required directly.
And the other part in the question is again a separate one from this.
You can try This, In very simple way
from django.contrib.auth.decorators import login_required
#login_required
def my_view(request):
return HttpResponse()
using #login_required means user have to login to access that view
Or If you you Want to use class then try this
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateView
class RestrictedView(LoginRequiredMixin, TemplateView):
template_name = 'foo/restricted.html'
raise_exception = True
permission_denied_message = "You are not allowed here."

Django-admin, Users and Permissions

In django an inactive user can't login, but if he is already logged in then he can still use the website until he logs out. Where i can to check why is not work correctly?
If you're worried about this, then you'd need to implement something to check the current user on every request and log them out explicitly if their account is inactive. Middleware would be a good place for this:
from django.contrib.auth import logout
class InactiveUserMiddleware(object):
def process_request(self, request):
if request.user.is_authenticated() and not request.user.is_active:
logout(request)
return redirect(your_login_url)
Place this in MIDDLEWARE_CLASSES directly after the AuthenticationMiddleware, and you should be good to do.

How to limit a view to superuser only?

view.py
#login_required
#permission_required('is_superuser')
def score_reset(request):
pass
url.py
url(r'^score-reset/$', score_reset, name='score-reset'),
I have the following code and to my surprise I still hit the function, despite being logged in with a non superuser. I was expecting to get a permission denied.
What am I missing?
is_superuser isn't a permission, it's an attribute on the user model. Django already has another decorator you can make use of called user_passes_test to perform this check:
from django.contrib.auth.decorators import user_passes_test
#user_passes_test(lambda u: u.is_superuser)
def score_reset(self,...):
...
allowing only super user login
Django is_staff permission decorator
Above answers seems to be for very early versions of django.
They are bit complicated than for the more later version
for django 1.11 here is a bit similar but simpler strategy.
views.py
from django.contrib.auth.decorators import login_required
#login_required
def some_view(request):
if request.user.is_superuser:
//allow access only to superuser
return render(request, 'app/template1.html', args)
else:
//allow access only to user
return render(request, 'app/template2.html', args)
Make use of Django's UserPassesTestMixin
Create a custom mixin SuperuserRequiredMixin
#mixins.py
from django.contrib.auth.mixins import UserPassesTestMixin
class SuperuserRequiredMixin(UserPassesTestMixin):
def test_func(self):
return self.request.user.is_superuser
Usage
class SomeSuperUserOnlyView(SuperuserRequiredMixin, ListView):
form_class = ExamForm
template_name = 'exam/newexam.html'
#user_passes_test is not an elegant solution if you want to perform this check on many views.
You can easily write your own decorathor having for example #staff_member_require.
Here you can see one of the possible solutions.
You can use the user passes test decorator to restrict access any way you want. Here is a restriction based on user email example:
from django.contrib.auth.decorators import user_passes_test
def email_check(user):
x = False
if user.email == 'anyemailhere':
x = True
return x
# Create your views here.
#user_passes_test(email_check)
def dash_index(request):
...
More here https://docs.djangoproject.com/en/2.1/topics/auth/default/#the-permission-required-decorator
SuperuserRequiredMixin
Another permission-based mixin. This is specifically for requiring a user to be a superuser. Comes in handy for tools that only privileged users should have access to.
First install: pip install django-braces
views.py
from braces.views import LoginRequiredMixin, SuperuserRequiredMixin
class SomeSuperuserView(LoginRequiredMixin, SuperuserRequiredMixin, TemplateView):
template_name = "path/to/template.html"

Django - what's the practice and most secure method of deleting or editing records for logged in users?

I have some sections on my web site where only logged in users can see their resources.
I also want to make absolutely sure that only that authorized user can modify and delete his/her records. What's the best practice and more secure way of accomplishing this in Django?
Real examples would be truly appreciated.
For my project, I created a Decorator that checked if the right user was logged in:
#decorator.py
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
def same_user_required(func):
def wrapper(request, user):
if not request.user.is_authenticated():
return HttpResponseRedirect(reverse('login-view'))
if not user == request.user.username:
return HttpResponseRedirect(reverse('login-view'))
return func(request, user)
return wrapper
You then add it to any views that need checking:
#view_profile.py
from apps.utilities.decorators import same_user_required
#same_user_required
def edit_profile(request, user):
Note that my URL contains the username /profile/edit/<username>, which is where the parameter comes from, in the edit_profile view.
Another way is to use the Django built-in decorator, user_passes_test (see Django Book Chap 14 for an example of its usage. You then just have to write the test, not the decorator boilerplate code.

Django permission_required error message?

I've added this decorator to one of my views
#permission_required('codename')
When a user visits that page and doesn't have the required permissions, he is redirected the login page, but it doesn't really tell him why he's been redirected there. Worse yet, if he logs in, and still doesn't have the permissions, he's going to be completely clueless as to why he can't access that page!
Isn't there a way I can tap into the messages framework and post an error at the same time?
Not sure what version of Django you are using, but in Django 1.4 and higher you can use:
from django.contrib.auth.decorators import permission_required
#permission_required('app.permission',raise_exception=True)
def myView(request):
#your view code
This will raise a 403 exception and if you have a 403.html page at the base of your template folder it will server this out.
If you are using class based views:
from django.views.generic.base import View
from django.contrib.auth.decorators import permission_required
from django.utils.decorators import method_decorator
class MyView(View):
#method_decorator(permission_required('app.permission',raise_exception=True)
def get(self, request):
#your GET view
Hope this helps.
You can tap into the messages framework and provide an error message. See my answer to an identical question.
You could use login_url parameter in this decorator to redirect to some other page, rather than login page. Or you can simply write your own decorator based on the code from django:
def permission_required(perm, login_url=None):
"""
Decorator for views that checks whether a user has a particular permission
enabled, redirecting to the log-in page if necessary.
"""
return user_passes_test(lambda u: u.has_perm(perm), login_url=login_url)
Simply change login_url to some redirect_to and it won't cause any confusion.
Use #permission_required_or_403('codename')
This will redirect the users to a 403 'permission denied' error page.