| 1 |
import datetime |
|---|
| 2 |
from django.core.exceptions import ImproperlyConfigured |
|---|
| 3 |
|
|---|
| 4 |
SESSION_KEY = '_auth_user_id' |
|---|
| 5 |
BACKEND_SESSION_KEY = '_auth_user_backend' |
|---|
| 6 |
REDIRECT_FIELD_NAME = 'next' |
|---|
| 7 |
|
|---|
| 8 |
def load_backend(path): |
|---|
| 9 |
i = path.rfind('.') |
|---|
| 10 |
module, attr = path[:i], path[i+1:] |
|---|
| 11 |
try: |
|---|
| 12 |
mod = __import__(module, {}, {}, [attr]) |
|---|
| 13 |
except ImportError, e: |
|---|
| 14 |
raise ImproperlyConfigured, 'Error importing authentication backend %s: "%s"' % (module, e) |
|---|
| 15 |
except ValueError, e: |
|---|
| 16 |
raise ImproperlyConfigured, 'Error importing authentication backends. Is AUTHENTICATION_BACKENDS a correctly defined list or tuple?' |
|---|
| 17 |
try: |
|---|
| 18 |
cls = getattr(mod, attr) |
|---|
| 19 |
except AttributeError: |
|---|
| 20 |
raise ImproperlyConfigured, 'Module "%s" does not define a "%s" authentication backend' % (module, attr) |
|---|
| 21 |
return cls() |
|---|
| 22 |
|
|---|
| 23 |
def get_backends(): |
|---|
| 24 |
from django.conf import settings |
|---|
| 25 |
backends = [] |
|---|
| 26 |
for backend_path in settings.AUTHENTICATION_BACKENDS: |
|---|
| 27 |
backends.append(load_backend(backend_path)) |
|---|
| 28 |
return backends |
|---|
| 29 |
|
|---|
| 30 |
def authenticate(**credentials): |
|---|
| 31 |
""" |
|---|
| 32 |
If the given credentials are valid, return a User object. |
|---|
| 33 |
""" |
|---|
| 34 |
for backend in get_backends(): |
|---|
| 35 |
try: |
|---|
| 36 |
user = backend.authenticate(**credentials) |
|---|
| 37 |
except TypeError: |
|---|
| 38 |
# This backend doesn't accept these credentials as arguments. Try the next one. |
|---|
| 39 |
continue |
|---|
| 40 |
if user is None: |
|---|
| 41 |
continue |
|---|
| 42 |
# Annotate the user object with the path of the backend. |
|---|
| 43 |
user.backend = "%s.%s" % (backend.__module__, backend.__class__.__name__) |
|---|
| 44 |
return user |
|---|
| 45 |
|
|---|
| 46 |
def login(request, user): |
|---|
| 47 |
""" |
|---|
| 48 |
Persist a user id and a backend in the request. This way a user doesn't |
|---|
| 49 |
have to reauthenticate on every request. |
|---|
| 50 |
""" |
|---|
| 51 |
if user is None: |
|---|
| 52 |
user = request.user |
|---|
| 53 |
# TODO: It would be nice to support different login methods, like signed cookies. |
|---|
| 54 |
user.last_login = datetime.datetime.now() |
|---|
| 55 |
user.save() |
|---|
| 56 |
request.session[SESSION_KEY] = user.id |
|---|
| 57 |
request.session[BACKEND_SESSION_KEY] = user.backend |
|---|
| 58 |
if hasattr(request, 'user'): |
|---|
| 59 |
request.user = user |
|---|
| 60 |
|
|---|
| 61 |
def logout(request): |
|---|
| 62 |
""" |
|---|
| 63 |
Remove the authenticated user's ID from the request. |
|---|
| 64 |
""" |
|---|
| 65 |
try: |
|---|
| 66 |
del request.session[SESSION_KEY] |
|---|
| 67 |
except KeyError: |
|---|
| 68 |
pass |
|---|
| 69 |
try: |
|---|
| 70 |
del request.session[BACKEND_SESSION_KEY] |
|---|
| 71 |
except KeyError: |
|---|
| 72 |
pass |
|---|
| 73 |
if hasattr(request, 'user'): |
|---|
| 74 |
from django.contrib.auth.models import AnonymousUser |
|---|
| 75 |
request.user = AnonymousUser() |
|---|
| 76 |
|
|---|
| 77 |
def get_user(request): |
|---|
| 78 |
from django.contrib.auth.models import AnonymousUser |
|---|
| 79 |
try: |
|---|
| 80 |
user_id = request.session[SESSION_KEY] |
|---|
| 81 |
backend_path = request.session[BACKEND_SESSION_KEY] |
|---|
| 82 |
backend = load_backend(backend_path) |
|---|
| 83 |
user = backend.get_user(user_id) or AnonymousUser() |
|---|
| 84 |
except KeyError: |
|---|
| 85 |
user = AnonymousUser() |
|---|
| 86 |
return user |
|---|