login CSRF verification failed. Request aborted - django

I extends AbstractBaseUser and I try to write login function but i got this error:
CSRF verification failed. Request aborted.
in views.py
def admin_login(request):
username = password = ''
if request.POST:
request.session.delete_test_cookie()
username = request.POST.get('username')
password = request.POST.get('password')
admin = Administrator.objects.all.get(username__exact=username)
if admin is not None and admin.check_password(password):
login(request, admin)
request.session['admin_id'] = admin.id
return redirect('dashborad')
return render_to_response('admin/login.html',{ 'username': username})

Keep in mind whenever you are using CSRF, you need to pass an instance of RequestContext back to the view. In addition, your form needs to have {% csrf_token %} added to it.
In your view code, you can use the render shortcut which will incude the correct context for you:
from django.shortcuts import render
def admin_login(request):
# your normal code
return render(request, 'admin/login.html', {'username': username})
The CSRF section of the documentation has a checklist of what is required in order for CSRF to work correctly.
You should also use authenticate() instead of writing your own logic:
from django.contrib.auth import authenticate
user = authenticate(username='john', password='secret')
Putting all that together, your code is now:
from django.shortcuts import render
from django.contrib.auth import authenticate
from django.contrib import messages
def admin_login(request):
"""Logs in an admin user, redirecting to the dashboard"""
if request.POST:
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(username, password)
if user is not None:
if user.is_active:
login(request, user)
request.session['admin_id'] = user.id
return redirect('dashboard')
else:
# do something because user was not active
messages.add_message(request, messages.ERROR, 'User Inactive')
return render(request, 'admin/login.html')
else:
# password/username combination was wrong
messages.add_message(request, messages.ERROR, 'Invalid Credentials')
return render(request, 'admin/login.html')
else:
return render(request, 'admin/login.html')
I am using the built-in messages framework to display the error messages.

Related

Django.contrib.auth.login is not working after i redirect to a different url

The login function is not working , after i call login , authenticated is set 'true' but after i redirect to 'main' view authenticated is set 'false'. How to keep the user logged in even after redirection?
class LoginForm(forms.Form):
user = forms.CharField()
password = forms.CharField()
def login(self):
try:
cred = users.objects.get(username = user)
if password==cred.password):
return (True, cred)
return (False, 'Invalid Password.')
except:
return (False, 'Not exist')
from django.contrib.auth import login as auth_login
def login(request):
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
valid, message = form.login()
if valid:
auth_login(request, message)
print(request.user.is_authenticated)
# this is not working
return redirect(main)
else:
return redirect(login)
form = LoginForm()
args = {'form': form}
return render(request, 'accounts/login.html', args)
def main(request):
print(request.user.is_authenticated)
You shouldn't write check your user credentials in form class. Do it in your login view. Example:
# views.py
from django.contrib.auth import authenticate, login
from django.urls import reverse
from django.shortcuts import redirect, render
def login_view(request): #changed_the name shouldn't be login
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data["username"]
password = form.cleaned_data["password"]
user = authenticate(username, password)
if user:
login(user)
return redirect(reverse("main"))
else:
return redirect(reverse("login"))
form = LoginForm()
args = {"form": form}
return render(request, 'accounts/login.html', args)
# urls.py
urlpatterns = [
path("login/", views.login_view, name="login"), # <-- really important
path("main/", views.main_view, name="main")
]
To summarize - to redirect to another page use redirect function. If you set name parameter in url of you view, you can reffer to this view using reverse. Also don't reinvent the wheel and write your own authentication function. Django provides: authenticate(username, password) and login(user) function.

Django #login_required decorator does not redirect to specific page

I'm trying to make a limited user edit page if the login is not executed.
After logging in, the edit page opens with any user_id in the url.
Although edit page should be open only with user_id already logged in user.
For example, I logged in with user_id=7, so only one next url (http://127.0.0.1:8000/user/7/edit) have to have access to edit page.
And this edit page is available by any next urls also (http://127.0.0.1:8000/user//edit)
Are there any errors or mistakes in my code?
I already have cleared cache in Opera and Chrome, but issue still exist.
Django ver. 1.11.9.
LOGIN_URL is not defined in settings.py
urls.py
urlpatterns = [
url(r'^login/$', user_login, name='user-login',),
url(r'^(?P<user_id>\d+)/edit$', user_edit, name='user-edit',),
]
views.py
def user_login(request):
login_form = AuthenticationForm(request.POST or None)
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user:
login(request, user)
print("next is {}".format(request.GET.get('next')))
return redirect(user_edit, user.id)
else:
return redirect(user_login)
return render(request, 'user_login.html', {'form': login_form})
#login_required(login_url='/user/login/')
def user_edit(request, user_id):
print(request, request.user)
print("next is {}".format(request.GET.get('next')))
return render(request, 'user_edit.html', {'userid': user_id, 'user': request.user})
The login_required decorator only checks that the user is logged in. If you want to check that the logged-in user has access to an object, then you need to do that in the view. For example:
from django.http import Http404
#login_required(login_url='/user/login/')
def user_edit(request, user_id):
print(request, request.user)
if request.user.id != user_id:
raise Http404
return render(request, 'user_edit.html', {'userid': user_id, 'user': request.user})

Previous 'session time out' error message is not being clean

I'm using Django 1.5.5, and I'm using the built-in authentication system provided by Django.
I define SESSION_TIMEOUT=600 in my settings.py, so after 10 minutes idle, user will be redirected to the login page with 'Session timed out' warning as request.COOKIES.logout_reason is displayed on the page.
The problem is, after user re-login again, and manually log out the system. The 'Session timed out' warning message is still displayed, I suppose that request.COOKIES.logout_reason variable should be cleaned up after successfully log in.
What could be the problem and where are the code I might need to look at? I'm inexperienced on Django and haven't found related discussion yet. Thanks.
Updated: the login and logout function I use in django.contrib.auth.views.py
from django.contrib.auth import REDIRECT_FIELD_NAME, login as auth_login, logout as auth_logout, get_user_model
from django.contrib.auth.decorators import login_required
from django.contrib.auth.forms import AuthenticationForm, PasswordResetForm, SetPasswordForm, PasswordChangeForm
from django.contrib.auth.tokens import default_token_generator
from django.contrib.sites.models import get_current_site
#sensitive_post_parameters()
#csrf_protect
#never_cache
def login(request, template_name='registration/login.html',
redirect_field_name=REDIRECT_FIELD_NAME,
authentication_form=AuthenticationForm,
current_app=None, extra_context=None):
"""
Displays the login form and handles the login action.
"""
redirect_to = request.REQUEST.get(redirect_field_name, '')
if request.method == "POST":
form = authentication_form(data=request.POST)
if form.is_valid():
# Ensure the user-originating redirection url is safe.
if not is_safe_url(url=redirect_to, host=request.get_host()):
redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL)
# Okay, security check complete. Log the user in.
auth_login(request, form.get_user())
if request.session.test_cookie_worked():
request.session.delete_test_cookie()
return HttpResponseRedirect(redirect_to)
else:
form = authentication_form(request)
request.session.set_test_cookie()
current_site = get_current_site(request)
context = {
'form': form,
redirect_field_name: redirect_to,
'site': current_site,
'site_name': current_site.name,
}
if extra_context is not None:
context.update(extra_context)
return TemplateResponse(request, template_name, context,
current_app=current_app)
def logout(request, next_page=None,
template_name='registration/logged_out.html',
redirect_field_name=REDIRECT_FIELD_NAME,
current_app=None, extra_context=None):
"""
Logs out the user and displays 'You are logged out' message.
"""
auth_logout(request)
if redirect_field_name in request.REQUEST:
next_page = request.REQUEST[redirect_field_name]
# Security check -- don't allow redirection to a different host.
if not is_safe_url(url=next_page, host=request.get_host()):
next_page = request.path
if next_page:
# Redirect to this page until the session has been cleared.
return HttpResponseRedirect(next_page)
current_site = get_current_site(request)
context = {
'site': current_site,
'site_name': current_site.name,
'title': _('Logged out')
}
if extra_context is not None:
context.update(extra_context)
return TemplateResponse(request, template_name, context,
current_app=current_app)
and the auth_login() and auth_logout() will call to the following functions in django.contrib.auth.__init__.py:
def login(request, user):
"""
Persist a user id and a backend in the request. This way a user doesn't
have to reauthenticate on every request. Note that data set during
the anonymous session is retained when the user logs in.
"""
if user is None:
user = request.user
# TODO: It would be nice to support different login methods, like signed cookies.
if SESSION_KEY in request.session:
if request.session[SESSION_KEY] != user.pk:
# To avoid reusing another user's session, create a new, empty
# session if the existing session corresponds to a different
# authenticated user.
request.session.flush()
else:
request.session.cycle_key()
request.session[SESSION_KEY] = user.pk
request.session[BACKEND_SESSION_KEY] = user.backend
if hasattr(request, 'user'):
request.user = user
rotate_token(request)
user_logged_in.send(sender=user.__class__, request=request, user=user)
def logout(request):
"""
Removes the authenticated user's ID from the request and flushes their
session data.
"""
# Dispatch the signal before the user is logged out so the receivers have a
# chance to find out *who* logged out.
user = getattr(request, 'user', None)
if hasattr(user, 'is_authenticated') and not user.is_authenticated():
user = None
user_logged_out.send(sender=user.__class__, request=request, user=user)
request.session.flush()
if hasattr(request, 'user'):
from django.contrib.auth.models import AnonymousUser
request.user = AnonymousUser()

Django : request.user not set after redirect

Specifically, after authentication and redirect, request.user is an anonymous user.
login (view function)
def login(request):
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
#django.contrib.auth.login
Login(request, form.get_user())
str = reverse('cm_base.views.index')
return HttpResponseRedirect(str)
else:
# Their password / email combination must have been incorrect
pass
else:
form = LoginForm()
return render_to_response('cm_base/login.html',
{"DEBUG": True,
'form' : form
},
context_instance=RequestContext(request))
in the index view, I removed the login_required decorator and tested the request.user object
def index(request):
test = request.user.is_authenticated()
return render_to_response('cm_base/index.html',
{"DEBUG": True,
"user": request.user,},
context_instance=RequestContext(request))
Test returns false.
Fix
I ended up just calling the index view directly. I am still confused as to why the user object was lost when I called HttpResponseRedirect.
def login(request):
if request.method == 'POST':
form = LoginForm(request.POST) # Not shown in this example
if form.is_valid():
Login(request, form.get_user())
str = reverse('cm_base.views.index')
return index(request)
else:
# Their password / email combination must have been incorrect
pass
else:
form = LoginForm()
A lot of things going on here that shouldn't be. First, you don't need to pass request.user, its available by default as long as you are using RequestContext, which you are.
Login() this method, what exactly is it doing? Django provides a built-in login method that you should be using if you are using the default authentication backend.
You are also not checking if a user is enabled or disabled.
Here is a different version of your code, adapted from the example in the documentation:
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login
def login_view(request):
form = LoginForm(request.POST or {})
ctx = {'form': form}
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = authenticate(username, password)
if not user:
ctx['errors'] = 'Invalid Login'
return render(request, 'login.html', ctx)
if not user.is_active:
ctx['errors'] = 'User is locked'
return render(request, 'login.html', ctx)
login(request, user)
return redirect('home')
else:
return render(request, 'login.html', ctx)
What auth backend are you using? If it is something other than the ModelBackend make sure your get_user method is correct. It sounds as if the auth middleware is sending a different identifier (like the pk instead of a username) than the one you are looking for in your get_user method.
This was the fix
<link rel="icon" href="{{ STATIC_URL }}img/favicon.ico" />
This file was missing from the static directory. The resulting 404 was breaking the user session.

Django empty error messages

I have an ajax login view. I can log in ok but when I log in incorrectly my json returns:
{"errors": {}}
My view is as follows:
def ajaxlogin(request):
from forms import LoginForm
form = LoginForm(request.POST)
logged_in = False
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if request.is_ajax() and user is not None:
login(request, user)
logged_in = True
return HttpResponse(simplejson.dumps({'redirect' : 'true'}), content_type='application/json')
else:
return HttpResponse(simplejson.dumps({'errors': dict(form.errors.items())}), content_type='application/json')
Any ideas?
If I use the login function without js enabled the form displays all the relevant error messages.
My LoginForm:
from django import forms
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth import authenticate
from django.utils.translation import ugettext_lazy as _
class LoginForm(AuthenticationForm):
username = forms.CharField(min_length=5, max_length=30,error_messages={'required':_("please enter a username"), 'min_length':_("username must be at least 5 characters"), 'max_length':_("username must be at less than 30 characters")})
password = forms.CharField(min_length=6, error_messages={'required':_("please enter a password"), 'min_length':_("password must be at least 6 characters")})
def clean(self):
username = self.cleaned_data.get('username')
password = self.cleaned_data.get('password')
if username and password:
self.user_cache = authenticate(username=username, password=password)
if self.user_cache is None:
raise forms.ValidationError(_("you have entered an incorrect username and/or password"))
elif not self.user_cache.is_active:
raise forms.ValidationError(_("This account is inactive."))
self.check_for_test_cookie()
return self.cleaned_data
You haven't shown us what your LoginForm looks like. Assuming it just has two CharFields, I wouldn't expect any errors as long as you have provided a user name and password.
To show errors for an invalid username and password combination, your form would have to include logic to authenticate the login data.
Luckily, you don't have write this yourself, you can use Django's built in AuthenticationForm. It will return an error if the username and password are not valid.
from django.contrib.auth.forms imoirt AuthenticationForm
from django.contrib.auth import login as auth_login
# in the view
if request.method == "POST":
form = AuthenticationForm(data=request.POST)
if form.is_valid():
# if the form is valid, the user has provided a valid
# username and password. We can get the user with the
# form.get_user method and log them in
auth_login(request, form.get_user())
# return suitable ajax responses
try something like:
return HttpResponse(simplejson.dumps({'errors': form.errors.as_text()}), content_type='application/json')