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()
Related
I am attaching my code in views and urls.py. Whenever the server runs, I want to see the login page first, but I am seeing an error that this page is not working.
#views.py
def loginPage(request):
if request.user.is_authenticated:
return redirect('/')
else:
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return redirect('/')
else:
messages.info(request, 'Username OR password is incorrect')
context = {}
return render(request, 'accounts/login.html', context)
# urls.py
urlpatterns = [
path('', views.loginPage, name="login"),
path('index/',views.index,name="index"),
You should pass #login_required decorator in your view. If you don't want to pass this decorator in your every view there are second way which you can do using middleware. In middleware you check the user is authenticated or not. If yes it redirects user to index page other way to login page. Here is an example:
Create middleware.py file and write this code inside it:
from django.utils.deprecation import MiddlewareMixin
from django.urls import reverse
from django.shortcuts import redirect
class LoginCheckMiddleWare(MiddlewareMixin):
def process_view(self, request, view_func, view_args, view_kwargs):
modulename = view_func.__module__
user = request.user # Who is the current user ?
if user.is_authenticated:
return redirect(reverse('index-page'))
else:
if request.path == reverse('login_page') or modulename == 'django.contrib.auth.views':
pass
else:
return redirect(reverse('login_page'))
After that add this line inside MIDDLEWARE in settings.py file:
'folder.middleware.LoginCheckMiddleWare', instead of folder write your middleware file located folder
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})
I have a custom user model. After doing successful login, I am getting the anonymous user in HttpResponseRedirect and templates as well. How do I get the logged in user?
Login View:
class LoginFormView(View):
form_class = UserLoginForm
user_model = get_user_model()
template_name = 'account/login.html'
def get(self, request, *args, **kwargs):
form = self.form_class
return render(request, self.template_name, {'form':form})
def post(self, request, *args, **kwargs):
email = request.POST['email']
password = request.POST['password']
user = authenticate(email=email, password=password)
if user is not None:
if user.is_active:
login(request, user)
return HttpResponseRedirect(reverse('home'))
else:
messages.error(request, 'Please enter correct email and password!')
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
If you have the request template context processor enabled, you'll be able to access the user in the template with {{ request.user}}.
Secondly, make sure you are importing the login function and not the login view. It should be:
from django.contrib.auth import login
The django usermodel django.contrib.auth.models.User has a field 'last_login' record the time when a user is successfully login.
But I donot see a code such as 'last_login=datetime.now()' in function from django.contrib.auth import login or from django.contrib.auth import authenticate. I also checked the django.contrib.auth.signals.user_logged_in.
where is the code for update the field 'last_login'?
Below is all the related source coede,how is the login process invoke the update_last_login? I don't see any code in login views or Authenticate function suoure code.
def update_last_login(sender, user, **kwargs):
"""
A signal receiver which updates the last_login date for
the user logging in.
"""
user.last_login = timezone.now()
user.save(update_fields=['last_login'])
user_logged_in.connect(update_last_login)
from django.dispatch import Signal
user_logged_in = Signal(providing_args=['request', 'user'])
#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(request, 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())
return HttpResponseRedirect(redirect_to)
else:
form = authentication_form(request)
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)
class ModelBackend(object):
"""
Authenticates against settings.AUTH_USER_MODEL.
"""
def authenticate(self, username=None, password=None, **kwargs):
UserModel = get_user_model()
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
try:
user = UserModel._default_manager.get_by_natural_key(username)
if user.check_password(password):
return user
except UserModel.DoesNotExist:
# Run the default password hasher once to reduce the timing
# difference between an existing and a non-existing user (#20760).
UserModel().set_password(password)
user_logged_in signal is connected to django.contrib.auth.models.update_last_login function, it makes:
user.last_login = timezone.now()
user.save(update_fields=['last_login'])
I think the best way of doing this thing is
request_user, data = requests.get_parameters(request)
user = requests.get_user_by_username(data['username'])
update_last_login(None, user)
You can also get user for request object by doing following.
user = request.user
on djnago 1.11
add this class :
class IsAuthenticated(BasePermission):
"""
Allows access only to authenticated users.
"""
def has_permission(self, request, view):
if request.user and request.user.is_authenticated:
user = request.user
user.last_login = timezone.now()
user.save(update_fields=['last_login'])
return request.user and request.user.is_authenticated
on setting file change :
'DEFAULT_PERMISSION_CLASSES': (
# custom class
'IsAuthenticated',
),
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.