Fixed #5612 -- Added login and logout signals to contrib auth app. Thanks SmileyChris and pterk.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@14710 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
81323cb119
commit
132afbf8ee
|
@ -2,6 +2,7 @@ import datetime
|
||||||
from warnings import warn
|
from warnings import warn
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.utils.importlib import import_module
|
from django.utils.importlib import import_module
|
||||||
|
from django.contrib.auth.signals import user_logged_in, user_logged_out
|
||||||
|
|
||||||
SESSION_KEY = '_auth_user_id'
|
SESSION_KEY = '_auth_user_id'
|
||||||
BACKEND_SESSION_KEY = '_auth_user_backend'
|
BACKEND_SESSION_KEY = '_auth_user_backend'
|
||||||
|
@ -62,8 +63,7 @@ def login(request, user):
|
||||||
if user is None:
|
if user is None:
|
||||||
user = request.user
|
user = request.user
|
||||||
# TODO: It would be nice to support different login methods, like signed cookies.
|
# TODO: It would be nice to support different login methods, like signed cookies.
|
||||||
user.last_login = datetime.datetime.now()
|
user_logged_in.send(sender=user.__class__, request=request, user=user)
|
||||||
user.save()
|
|
||||||
|
|
||||||
if SESSION_KEY in request.session:
|
if SESSION_KEY in request.session:
|
||||||
if request.session[SESSION_KEY] != user.id:
|
if request.session[SESSION_KEY] != user.id:
|
||||||
|
@ -83,6 +83,13 @@ def logout(request):
|
||||||
Removes the authenticated user's ID from the request and flushes their
|
Removes the authenticated user's ID from the request and flushes their
|
||||||
session data.
|
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()
|
request.session.flush()
|
||||||
if hasattr(request, 'user'):
|
if hasattr(request, 'user'):
|
||||||
from django.contrib.auth.models import AnonymousUser
|
from django.contrib.auth.models import AnonymousUser
|
||||||
|
|
|
@ -2,6 +2,7 @@ import datetime
|
||||||
import urllib
|
import urllib
|
||||||
|
|
||||||
from django.contrib import auth
|
from django.contrib import auth
|
||||||
|
from django.contrib.auth.signals import user_logged_in
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models.manager import EmptyManager
|
from django.db.models.manager import EmptyManager
|
||||||
|
@ -40,6 +41,15 @@ def check_password(raw_password, enc_password):
|
||||||
algo, salt, hsh = enc_password.split('$')
|
algo, salt, hsh = enc_password.split('$')
|
||||||
return hsh == get_hexdigest(algo, salt, raw_password)
|
return hsh == get_hexdigest(algo, salt, raw_password)
|
||||||
|
|
||||||
|
def update_last_login(sender, user, **kwargs):
|
||||||
|
"""
|
||||||
|
A signal receiver which updates the last_login date for
|
||||||
|
the user logging in.
|
||||||
|
"""
|
||||||
|
user.last_login = datetime.datetime.now()
|
||||||
|
user.save()
|
||||||
|
user_logged_in.connect(update_last_login)
|
||||||
|
|
||||||
class SiteProfileNotAvailable(Exception):
|
class SiteProfileNotAvailable(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
from django.dispatch import Signal
|
||||||
|
|
||||||
|
user_logged_in = Signal(providing_args=['request', 'user'])
|
||||||
|
user_logged_out = Signal(providing_args=['request', 'user'])
|
|
@ -5,6 +5,7 @@ from django.contrib.auth.tests.forms import UserCreationFormTest, Authentication
|
||||||
from django.contrib.auth.tests.remote_user \
|
from django.contrib.auth.tests.remote_user \
|
||||||
import RemoteUserTest, RemoteUserNoCreateTest, RemoteUserCustomTest
|
import RemoteUserTest, RemoteUserNoCreateTest, RemoteUserCustomTest
|
||||||
from django.contrib.auth.tests.models import ProfileTestCase
|
from django.contrib.auth.tests.models import ProfileTestCase
|
||||||
|
from django.contrib.auth.tests.signals import SignalTestCase
|
||||||
from django.contrib.auth.tests.tokens import TokenGeneratorTest
|
from django.contrib.auth.tests.tokens import TokenGeneratorTest
|
||||||
from django.contrib.auth.tests.views \
|
from django.contrib.auth.tests.views \
|
||||||
import PasswordResetTest, ChangePasswordTest, LoginTest, LogoutTest
|
import PasswordResetTest, ChangePasswordTest, LoginTest, LogoutTest
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
from django.contrib.auth import signals
|
||||||
|
|
||||||
|
|
||||||
|
class SignalTestCase(TestCase):
|
||||||
|
urls = 'django.contrib.auth.tests.urls'
|
||||||
|
fixtures = ['authtestdata.json']
|
||||||
|
|
||||||
|
def listener_login(self, user, **kwargs):
|
||||||
|
self.logged_in.append(user)
|
||||||
|
|
||||||
|
def listener_logout(self, user, **kwargs):
|
||||||
|
self.logged_out.append(user)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
"""Set up the listeners and reset the logged in/logged out counters"""
|
||||||
|
self.logged_in = []
|
||||||
|
self.logged_out = []
|
||||||
|
signals.user_logged_in.connect(self.listener_login)
|
||||||
|
signals.user_logged_out.connect(self.listener_logout)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
"""Disconnect the listeners"""
|
||||||
|
signals.user_logged_in.disconnect(self.listener_login)
|
||||||
|
signals.user_logged_out.disconnect(self.listener_logout)
|
||||||
|
|
||||||
|
def test_login(self):
|
||||||
|
# Only a successful login will trigger the signal.
|
||||||
|
self.client.login(username='testclient', password='bad')
|
||||||
|
self.assertEqual(len(self.logged_in), 0)
|
||||||
|
# Like this:
|
||||||
|
self.client.login(username='testclient', password='password')
|
||||||
|
self.assertEqual(len(self.logged_in), 1)
|
||||||
|
self.assertEqual(self.logged_in[0].username, 'testclient')
|
||||||
|
|
||||||
|
def test_logout_anonymous(self):
|
||||||
|
# The log_out function will still trigger the signal for anonymous
|
||||||
|
# users.
|
||||||
|
self.client.get('/logout/next_page/')
|
||||||
|
self.assertEqual(len(self.logged_out), 1)
|
||||||
|
self.assertEqual(self.logged_out[0], None)
|
||||||
|
|
||||||
|
def test_logout(self):
|
||||||
|
self.client.login(username='testclient', password='password')
|
||||||
|
self.client.get('/logout/next_page/')
|
||||||
|
self.assertEqual(len(self.logged_out), 1)
|
||||||
|
self.assertEqual(self.logged_out[0].username, 'testclient')
|
|
@ -12,6 +12,9 @@ A list of all the signals that Django sends.
|
||||||
The :doc:`comment framework </ref/contrib/comments/index>` sends a :doc:`set
|
The :doc:`comment framework </ref/contrib/comments/index>` sends a :doc:`set
|
||||||
of comment-related signals </ref/contrib/comments/signals>`.
|
of comment-related signals </ref/contrib/comments/signals>`.
|
||||||
|
|
||||||
|
The :ref:`authentication framework <topics-auth>` sends :ref:`signals when
|
||||||
|
a user is logged in / out <topics-auth-signals>`.
|
||||||
|
|
||||||
Model signals
|
Model signals
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
|
|
@ -665,6 +665,44 @@ How to log a user out
|
||||||
immediately after logging out, do that *after* calling
|
immediately after logging out, do that *after* calling
|
||||||
:func:`django.contrib.auth.logout()`.
|
:func:`django.contrib.auth.logout()`.
|
||||||
|
|
||||||
|
.. _topics-auth-signals:
|
||||||
|
|
||||||
|
Login and logout signals
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
The auth framework uses two :ref:`signals <topic-signals>` that can be used for
|
||||||
|
notification when a user logs in or out.
|
||||||
|
|
||||||
|
**:data:`django.contrib.auth.signals.user_logged_in`**
|
||||||
|
|
||||||
|
Sent when a user logs in successfully.
|
||||||
|
|
||||||
|
Arguments sent with this signal:
|
||||||
|
|
||||||
|
``sender``
|
||||||
|
As above: the class of the user that just logged in.
|
||||||
|
|
||||||
|
``request``
|
||||||
|
The current :class:`~django.http.HttpRequest` instance.
|
||||||
|
|
||||||
|
``user``
|
||||||
|
The user instance that just logged in.
|
||||||
|
|
||||||
|
**:data:`django.contrib.auth.signals.user_logged_out`**
|
||||||
|
|
||||||
|
Sent when the logout method is called.
|
||||||
|
|
||||||
|
``sender``
|
||||||
|
As above: the class of the user that just logged out or ``None``
|
||||||
|
if the user was not authenticated.
|
||||||
|
|
||||||
|
``request``
|
||||||
|
The current :class:`~django.http.HttpRequest` instance.
|
||||||
|
|
||||||
|
``user``
|
||||||
|
The user instance that just logged out or ``None`` if the
|
||||||
|
user was not authenticated.
|
||||||
|
|
||||||
Limiting access to logged-in users
|
Limiting access to logged-in users
|
||||||
----------------------------------
|
----------------------------------
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue