Restrict unauthorised access in Django - 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."

Related

how can i overide django allauth signup success_url

I'm working on a project using allauth and i'm using customer user model and i wan the newly registered user to be redirected to a different page (say profile form page) which will be totally different from the login_redirect_url, I have tried it this way
any idea how i can make this work pls?
from django.shortcuts import get_object_or_404, redirect, render
from allauth.account.views import LogoutView
from django.urls import reverse_lazy
from allauth.account.views import SignupView
from django.views.generic import TemplateView
from .models import CustomUser
class Signup(SignupView):
success_url = reverse_lazy('business:company_profile')
def get_success_url(self):
return self.success_url
I am not sure there is way to override SignUp redirection since when you sign up in the application, you also sign in, which will use the login_redirect_url.
If you overrode login_redirect_url (documentation) you can update your logic and redirect the user to his profile if some fields are missing/empty?
def get_login_redirect_url(self, request):
if not request.user.your_custom_field:
path = "/accounts/{username}/"
return path.format(username=request.user.username)
else
return "/"
You could also implement another logic by adding a bool is_first_visit on your CustomerUser model (with default=True) and set it to False after his first visit.
Is the code that you proposed not working? What errors does it produce?
On first glance, the view that you've proposed should work. You would just have to make sure it's being used in "urls.py".

Django-allauth: PasswordChangeView override of success_url with logged out user results in error

When changing a password via django-allauth, the default redirect after successfully posting the password change is again the password change template. Since I find this confusing, I overrode the original PasswordChnageView in my views.py file:
from allauth.account.views import PasswordChangeView
from django.urls import reverse_lazy
class MyPasswordChangeView(PasswordChangeView):
success_url = reverse_lazy('home')
and changed my urls.py file:
from django.urls import path, include
from users.views import MyPasswordChangeView
urlpatterns = [
...
# User management
path('accounts/password/change/', MyPasswordChangeView.as_view(), name="account_change_password"),
path('accounts/', include('allauth.urls')),
...
]
This works fine when the user is logged in, however when I try to access the url http://127.0.0.1:8000/accounts/password/change/ while being logged out, I get the following error message: AttributeError at /accounts/password/change/ 'AnonymousUser' object has no attribute 'has_usable_password'
Before I created my custom override, the result of the same behaviour was that I was redirected to the login url http://127.0.0.1:8000/accounts/login/?next=/
What do I need to change with my custom view, to redirect to the login url when a logged out user tries to acces the url http://127.0.0.1:8000/accounts/password/change/
Look at the source code: The PasswordChangeView from allauth doesn't have the login required decorator in itself, that's added directly in the urls: the view used is password_change = login_required(PasswordChangeView.as_view()).
There are 2 ways:
Add login_required decorator to your URL.
from django.contrib.auth.decorators import login_required
path('accounts/password/change/', login_required(MyPasswordChangeView.as_view()), name="account_change_password"),
Inherit from LoginRequiredMixin.
from django.contrib.auth.mixins import LoginRequiredMixin
class MyPasswordChangeView(LoginRequiredMixin, PasswordChangeView):
success_url = reverse_lazy('home')
Make sure that LoginRequiredMixin is to the left most side of your child class.

Django restrict access to TemplateView

I'm using TemplateView to display swagger pages (local files). However, now I need to restrict access. Using a normal view, I could use #login_required mixin on the view. Is there a way to do that with TemplateViews? Or should I be using some other way of displaying these swagger pages?
url(r'^swagger/', TemplateView.as_view(template_name='swagger.html'), name='swagger'),
The most clean way would be to create a view extending the TemplateView, so it would help leaving your urls.py clean.
views.py
from django.contrib.auth.mixins import LoginRequiredMixin
class SwaggerView(LoginRequiredMixin, TemplateView):
template_name = 'swagger.html'
urls.py
from . import views
url(r'^swagger/', views.SwaggerView.as_view(), name='swagger'),

Django Authentication process

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.

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.