django - method PUT - Forbidden (CSRF cookie not set.): - django

My function view for method PUT is:
return JsonResponse ({})
Using HttpRequester (addon for firefox)
I get CSRF verification failed. Request aborted.
print(request) give following result:
Forbidden (CSRF cookie not set.): /test/src/4213
I don't know what I should do. Could you help me please ?
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^test/src/(\d+)', MyView.as_view(), name='put_'),
]
class MyView(View):
....
def put(self, request, *args, **kwargs):
print(request)
return JsonResponse({})
I have no form so I can't include {%csrf_token%}. I have no html file. I try to test it with HttpRequester (firefox addon)

Make sure that if you are submitting a form you {%csrf_token%} as a hidden input in your form.
Also, check to make sure that CsrfViewMiddleware is in your MIDDLEWARE_CLASSES in settings.py

If this view is not for a form but to be accessed directly by something you can remove csrf checks with csrf_exempt decorator :
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^test/src/(\d+)', csrf_exempt(MyView.as_view()), name='put_'),
]

Related

How to set custom admin login URL in Django Admin on session timeout?

I wrote a Django app which has an external authentication system reacheable at some URL (say, https://.../myproject/login). This is working well.
However, when the session expires, the user gets redirected to the default login url which is https://.../myproject/admin). I'd like to change the behavior of the app so if the session expires, the user should be redirected to https://.../myproject/login and only use the /admin login when explicitly opened.
Is there a built-in way to do this in Django?
Django admin redirects the users to /admin/login when the session is expired or session is missing.
There are several ways to redirect users to https://.../myproject/login instead of https://.../myproject/admin/login.
Approach 1:
Override the view of myproject/admin/login URL with the view of myproject/login.
Let's say that myproject/login uses LoginView to render external system's login page, then add url(r'^admin/login/?$', LoginView.as_view(), name='admin:login') just above url(r'^admin/', include(admin.site.urls)) in myproject/myproject/urls.py
urlpatterns = [
url(r'^admin/login/?$', LoginView.as_view(), name='admin:login'),
url(r'^admin/', include(admin.site.urls)),
]
Pros:
Render the external system's login page instead of default Django admin login page on /myproject/admin/login
Cons:
The URL still points to myproject/admin/login
No way to access the default admin login page
Approach 2:
Override the view of myproject/admin/login url and redirect the user to myproject/login
Lets create a new view AdminLoginView then add url(r'^admin/login/?$', AdminLoginView.as_view(), name='admin:login') just above url(r'^admin/', include(admin.site.urls)) in myproject/myproject/urls.py
from django.core.urlresolvers import reverse
class AdminLoginView(TemplateView):
def get(self, request, *args, **kwargs):
"""
Assuming the name of the external system's login url is "login"
"""
return HttpResponseRedirect(reverse('login'))
urlpatterns = [
url(r'^admin/login/?$', AdminLoginView.as_view(), name='admin:login'),
url(r'^admin/default-login/?$', admin.site.login, name='default-admin-login'),
url(r'^admin/', include(admin.site.urls)),
]
Pros:
The URL changes to myproject/login
Cons:
You have to add extra code for the default login page.
I would recommend approach 2 to solve the problem mentioned in the question.
Thanks.
You can use LOGIN_URL and LOGOUT_REDIRECT_URL
https://docs.djangoproject.com/en/2.2/ref/settings/#login-url
Redirect to myproject/login for login (Default redirects to /accounts/login/)
LOGIN_URL = '/myproject/login/'
Redirect to the login page after log out (Default to None).
LOGOUT_REDIRECT_URL = '/myproject/login/'
IMO the best possible solution is to override the function for login view.
To do this add these lines of code in your urls.py containing the 'admin/'
# urls.py
def login(request):
if request.user and request.user.is_authenticated and request.user.is_active and request.user.is_staff:
return HttpResponseRedirect(reverse('admin:index', current_app='admin'))
else:
return HttpResponseRedirect(reverse('index', current_app='your_app_name'))
admin.site.login = login
# The lines below probably exist
# urlpatterns = [
# path('admin/', admin.site.urls),
# path('', include('your_app.urls')),
# ]

Django 1.10: login required middleware redirect loop

I'm writing a bit of middleware to effectively make #login_required on all pages. Unfortunately what I've got results in a redirect loop.
The implementation is using "old" style middleware with 1.10 via MiddlewareMixin and process_request() hook in attempt to redirect to login page whenever the user is not authenticated.
First, I'm using the default auth urls django.contrib.auth.urls. The docs say:
This will include the following URL patterns: ^login/$ [name='login']...
# main URLConf urls.py
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^', include('django.contrib.auth.urls')), # https://docs.djangoproject.com/en/1.10/topics/auth/default/#module-django.contrib.auth.views
]
Then here's the middleware (yes it's added to MIDDLEWARE in settings.py):
from django.http import HttpResponseRedirect
from django.utils.deprecation import MiddlewareMixin
class LoginRequiredMiddleware(MiddlewareMixin):
def process_request(self, request):
if not request.user.is_authenticated():
return HttpResponseRedirect('/login/')
The login page/functionality works fine when the my middleware isn't included, while including it results in every url causing ERR_TOO_MANY_REDIRECTS.
What am I missing? Thanks.
Doh! I needed to check for /login/ in process_request and ignore it.
Here's a simplified version of what is implemented. The real version uses settings.py and regexes to define the login exempt urls. Much credit to Ryan Witt's post on this approach.
class LoginRequiredMiddleware(MiddlewareMixin):
def process_request(self, request):
if not request.user.is_authenticated():
path = request.path_info.lstrip('/')
# If path is not root url ('') and path is not exempt from authentication
if not path or not any(path != eu for eu in ["/login", "admin"]):
return HttpResponseRedirect("/login/")

Django PermissionRequiredMixin not working when user doesn't have the permission required

Okay i have this view and im using django PermissionRequiredMixin, when the user has the change_item permission i specify there all works fine
from django.contrib.auth.mixins import PermissionRequiredMixin
class MyView(PermissionRequiredMixin,View):
template = 'myapp/item_detail.html'
permission_required = 'myapp.change_item'
def get(self, request, *args, **kwargs):
#Query here
return render(request, self.template)
But,when user doesn't have it, i got a 404 error page saying that myapp/login it's not valid:
**Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/myapp/login?next=/myapp/item/35/**
The current URL, myapp/login, didn't match any of these.
That login it's set in settings LOGIN_URL and works perfectly with everything else...but not with this, and i also see that a login string it's in the middle of the url from the error...am i missing something about mixins ?, what am i doing wrong ??
I add the urls.py :
from django.conf.urls import url
from .views.views_home import HomeView, WelcomeView
from .views.views_authentication import LoginView, LogoutView, ChangePasswordView
urlpatterns = [
url(r'^welcome/$', WelcomeView.as_view(), name="welcome"),
url(r'^home/$', HomeView.as_view(), name="home"),
url(r'^login/$', LoginView.as_view(), name="login"),
url(r'^logout/$', LogoutView, name="logout"),
url(r'^change_password/$', ChangePasswordView.as_view(), name="change_password"),
]
And the stack trace:
[03/Oct/2016 17:04:47] "GET /myapp/item/35/ HTTP/1.1" 302 0
Not Found: /myapp/login
[03/Oct/2016 17:04:47] "GET /myapp/login?next=/myapp/item/35/ HTTP/1.1" 404 32312
Thanks in advance !!
When using the PermissionRequiredMixin, you can use the LOGIN_URL in settings.py to redirect the user to the current page. if myapp/login/ isn't the correct location, please use this setting to specify the right one. Also instead of using settings.LOGIN_URL, you can add a login_url class member to your view or you can add a get_login_url() method.
All of these things assume that myapp/login isn't the correct location, if that's indeed where you want the user redirected to, that means you have an error in urls.py
Last but not least, when using DRF, it's customary to use DjangoModelPermissions instead of PermissionRequiredMixin

Can login_required by applied to an entire app?

Is there a way I can apply the login_required decorator to an entire app? When I say "app" I mean it in the django sense, which is to say a set of urls and views, not an entire project.
Yes, you should use middleware.
Try to look through solutions which have some differences:
http://www.djangosnippets.org/snippets/1179/ - with list of exceptions.
http://www.djangosnippets.org/snippets/1158/ - with list of exceptions.
http://www.djangosnippets.org/snippets/966/ - conversely with list of login required urls.
http://www.djangosnippets.org/snippets/136/ - simplest.
As of Django 3+, you can set login_require() to an entire app by applying a middleware. Do like followings:
Step 1: Create a new file anything.py in your yourapp directory and write the following:
import re
from django.conf import settings
from django.contrib.auth.decorators import login_required
//for registering a class as middleware you at least __init__() and __call__()
//for this case we additionally need process_view() which will be automatically called by Django before rendering a view/template
class ClassName(object):
//need for one time initialization, here response is a function which will be called to get response from view/template
def __init__(self, response):
self.get_response = response
self.required = tuple(re.compile(url) for url in settings.AUTH_URLS)
self.exceptions = tuple(re.compile(url)for url in settings.NO_AUTH_URLS)
def __call__(self, request):
//any code written here will be called before requesting response
response = self.get_response(request)
//any code written here will be called after response
return response
//this is called before requesting response
def process_view(self, request, view_func, view_args, view_kwargs):
//if authenticated return no exception
if request.user.is_authenticated:
return None
//return login_required()
for url in self.required:
if url.match(request.path):
return login_required(view_func)(request, *view_args, **view_kwargs)
//default case, no exception
return None
Step 2: Add this anything.py to Middleware[] in project/settings.py like followings
MIDDLEWARE = [
// your previous middleware
'yourapp.anything.ClassName',
]
Step 3: Also add the following snippet into project/settings.py
AUTH_URLS = (
//disallowing app url, use the url/path that you added on mysite/urls.py (not myapp/urls.py) to include as your app urls
r'/your_app_url(.*)$',
)
I think you are looking for this snippet, containing login-required middleware.
This is an old question. But here goes:
Django Decorator Include
This is a substitute of include in URLConf. Pefect for applying login_required to an entire app.
I clicked all the links in the anwsers, but they were all based on some kind of regular expressions. On Django 3+ you can do the following to restrict for a specific app:
Declare app_name="myapp" in your app's urls.py (https://docs.djangoproject.com/en/3.2/intro/tutorial03/#namespacing-url-names)
(now all these urls should be called with there namespace "myapp:urlname")
Create a middleware.py file in your app with this:
from django.contrib.auth.views import redirect_to_login
from django.core.exceptions import ImproperlyConfigured
from django.urls import resolve
class LoginRequiredAccess:
"""All urls starting with the given prefix require the user to be logged in"""
APP_NAME = 'myapp'
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if not hasattr(request, 'user'):
raise ImproperlyConfigured(
"Requires the django's authentication middleware"
" to be installed.")
user = request.user
if resolve(request.path).app_name == self.APP_NAME: # match app_name defined in myapp.urls.py
if not user.is_authenticated:
path = request.get_full_path()
return redirect_to_login(path)
return self.get_response(request)
Put "myapp.middleware.LoginRequiredAccess" in your MIDDLEWARE constant from settings.py
Then in your main project urls.py
urlpatterns = [
path('foobar', include('otherapp.urls')), # this will not be redirected
path('whatever', include('myapp.urls')), # all these urls will be redirected to login
]
On of the avantage of this method is it can still works with a root url path, e.g path('', include('myapp.urls')), while the others will do an infinite redirect loop.
I'm wondering if there is any solution to make it works like this:
/app/app.py
class AppConfig(AppConfig):
login_required = True
/project/urls.py
urlpatterns = [
url(r'app/', include('app.urls', namespace='app'))
]
/common/middleare.py
def LogMiddleware(get_response):
def middleware(request):
# solution 1
app = get_app(request)
if app.login_required is True and request.is_authenticated is Fasle:
return HttpResponseRedirect(redirect_url)
# solution 2
url_space = get_url_space(request.get_raw_uri())
if url_space.namespace in ['app', 'admin', 'staff', 'manage'] and \
request.is_authenticated is False:
return HttpResponseRedirect(redirect_url)
I will check if there is any methoded to get the app or url name of a request. I think it looks prettier.

Django: Redirect logged in users from login page

I want to set up my site so that if a user hits the /login page and they are already logged in, it will redirect them to the homepage. If they are not logged in then it will display normally. How can I do this since the login code is built into Django?
I'm assuming you're currently using the built-in login view, with
(r'^accounts/login/$', 'django.contrib.auth.views.login'),
or something similar in your urls.
You can write your own login view that wraps the default one. It will check if the user is already logged in (through is_authenticated attribute official documentation) and redirect if he is, and use the default view otherwise.
something like:
from django.contrib.auth.views import login
def custom_login(request):
if request.user.is_authenticated:
return HttpResponseRedirect(...)
else:
return login(request)
and of course change your urls accordingly:
(r'^accounts/login/$', custom_login),
The Django 1.10 way
For Django 1.10, released in August 2016, a new parameter named redirect_authenticated_user was added to the login() function based view present in django.contrib.auth [1].
Example
Suppose we have a Django application with a file named views.py and another file named urls.py. The urls.py file will contain some Python code like this:
#
# Django 1.10 way
#
from django.contrib.auth import views as auth_views
from . import views as app_views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/', auth_views.login, name='login',
kwargs={'redirect_authenticated_user': True}),
url(r'^dashboard/', app_views.Dashboard.as_view(), name='dashboard'),
url(r'^$', TemplateView.as_view(template_name='index.html'), name='index'),
]
From that file, the relevant part within the urlpatterns variable definition is the following, which uses the already mentioned redirect_authenticated_user parameter with a True value:
url(r'^login/', auth_views.login, name='login',
kwargs={'redirect_authenticated_user': True}),
Take note that the default value of the redirect_authenticated_user parameter is False.
The Django 1.11 way
For Django 1.11, released in April 2017, the LoginView class based view superseded the login() function based view [2], which gives you two options to choose from:
Use the same Django 1.10 way just described before, which is a positive thing because your current code will continue working fine. If you tell Python interpreter to display warnings, by for example running in a console terminal the command python -Wd manage.py runserver in your Django project directory and then going with a web browser to your login page, you would see in that same console terminal a warning message like this:
/usr/local/lib/python3.6/site-packages/django/contrib/auth/views.py:54:
RemovedInDjango21Warning: The login() view is superseded by the
class-based LoginView().
Use the new Django 1.11 way, which will make your code more modern and compatible with future Django releases. With this option, the example given before will now look like the following one:
Example
We again suppose that we have a Django application with a file named views.py and another file named urls.py. The urls.py file will contain some Python code like this:
#
# Django 1.11 way
#
from django.contrib.auth import views as auth_views
from . import views as app_views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/',
auth_views.LoginView.as_view(redirect_authenticated_user=True),
name='login'),
url(r'^dashboard/', app_views.Dashboard.as_view(), name='dashboard'),
url(r'^$', TemplateView.as_view(template_name='index.html'), name='index'),
]
From that file, the relevant part within the urlpatterns variable definition is the following, which again uses the already mentioned redirect_authenticated_user parameter with a True value, but passing it as an argument to the as_view method of the LoginView class:
url(r'^login/',
auth_views.LoginView.as_view(redirect_authenticated_user=False),
name='login'),
Take note that here the default value of the redirect_authenticated_user parameter is also False.
References
[1] Relevant section in Django 1.10 release notes at https://docs.djangoproject.com/en/dev/releases/1.10/#django-contrib-auth
[2] Relevant section in Django 1.11 release notes at https://docs.djangoproject.com/en/1.11/releases/1.11/#django-contrib-auth
anonymous_required decorator
For class based views
Code:
from django.shortcuts import redirect
def anonymous_required(func):
def as_view(request, *args, **kwargs):
redirect_to = kwargs.get('next', settings.LOGIN_REDIRECT_URL )
if request.user.is_authenticated():
return redirect(redirect_to)
response = func(request, *args, **kwargs)
return response
return as_view
Usage:
url(r'^/?$',
anonymous_required(auth_views.login),
),
url(r'^register/?$',
anonymous_required(RegistrationView.as_view()),
name='auth.views.register'
),
# Could be used to decorate the dispatch function of the view instead of the url
For view functions
From http://blog.motane.lu/2010/01/06/django-anonymous_required-decorator/
Code:
from django.http import HttpResponseRedirect
def anonymous_required( view_function, redirect_to = None ):
return AnonymousRequired( view_function, redirect_to )
class AnonymousRequired( object ):
def __init__( self, view_function, redirect_to ):
if redirect_to is None:
from django.conf import settings
redirect_to = settings.LOGIN_REDIRECT_URL
self.view_function = view_function
self.redirect_to = redirect_to
def __call__( self, request, *args, **kwargs ):
if request.user is not None and request.user.is_authenticated():
return HttpResponseRedirect( self.redirect_to )
return self.view_function( request, *args, **kwargs )
Usage:
#anonymous_required
def my_view( request ):
return render_to_response( 'my-view.html' )
For Django 2.x, in your urls.py:
from django.contrib.auth import views as auth_views
from django.urls import path
urlpatterns = [
path('login/', auth_views.LoginView.as_view(redirect_authenticated_user=True), name='login'),
]
Add this decorator above your login view to redirect to /home if a user is already logged in
#user_passes_test(lambda user: not user.username, login_url='/home', redirect_field_name=None)
and don't forget to import the decorator
from django.contrib.auth.decorators import user_passes_test
Since class based views (CBVs) is on the rise. This approach will help you redirect to another url when accessing view for non authenticated users only.
In my example the sign-up page overriding the dispatch() method.
class Signup(CreateView):
template_name = 'sign-up.html'
def dispatch(self, *args, **kwargs):
if self.request.user.is_authenticated:
return redirect('path/to/desired/url')
return super().dispatch(*args, **kwargs)
Cheers!
https://docs.djangoproject.com/en/3.1/topics/auth/default/#all-authentication-views
Add the redirect route in settings
LOGIN_URL = 'login'
And in the URLs add redirect_authenticated_user=True to LoginView
path('login/', auth_views.LoginView.as_view(template_name='users/login.html',redirect_authenticated_user=True), name='login')
I know this is a pretty old question, but I'll add my technique in case anyone else needs it:
myproject/myapp/views/misc.py
from django.contrib.auth.views import login as contrib_login, logout as contrib_logout
from django.shortcuts import redirect
from django.conf import settings
def login(request, **kwargs):
if request.user.is_authenticated():
return redirect(settings.LOGIN_REDIRECT_URL)
else:
return contrib_login(request, **kwargs)
logout = contrib_logout
myproject/myapp/urls.py
from django.conf.urls import patterns, url
urlpatterns = patterns('myapp.views.misc',
url(r'^login/$', 'login', {'template_name': 'myapp/login.html'}, name='login'),
url(r'^logout/$', 'logout', {'template_name': 'myapp/logout.html'}, name='logout'),
)
...
Assuming that you are done setting up built-in Django user authentication (and using decorators), add this in your settings.py:
LOGIN_REDIRECT_URL = '/welcome/'
NOTE: '/welcome/' here is the URL of the homepage. It is up to you what to replace it with.
All you have to do is set the "root" url to the homepage view. Since the homepage view is already restricted for logged on users, it'll automatically redirect anonymous users to the login page.
Kepp the url as it is.
And add something like:
(r'^$', 'my_project.my_app.views.homepage'),