Es posible integrar Django con un sistema de autentificación existente — otra fuente de nombres de usuario y contraseñas o métodos de autentificación.
Por ejemplo, tu compañía ya puede tener una configuración LDAP que almacena un nombre de usuario y contraseña para cada empleado. Sería una molestia tanto para el administrador de red como para los usuarios, si cada uno de ellos tiene cuentas separadas en LDAP y en las aplicaciones basadas en Django.
Para manejar situaciones como ésta, el sistema de autentificación de Django te permite conectarte con otras fuentes de autentificación. Puedes anular el esquema por omisión de Django basado en base de datos, o puedes usar el sistema por omisión en conjunto con otros sistemas.
16.2.1. Especificar los back-ends de autentificación
Detrás de escena, Django mantiene una lista de "back-ends de autentificación"
que utiliza para autentificar. Cuando alguien llama a
django.contrib.auth.authenticate()
(como se describió en el Capítulo 12),
Django intenta autentificar usando todos sus back-ends de autentificación. Si
el primer método de autentificación falla, Django intenta con el segundo, y así
sucesivamente, hasta que todos los back-ends han sido intentados.
La lista de back-ends de autentificación a usar se especifica en la
configuración AUTHENTICATION_BACKENDS
. Ésta debe ser una tupla de nombres de
ruta Python que apuntan a clases que saben cómo autentificar. Estas clases
pueden estar en cualquier lugar de tu ruta Python.
Por omisión, AUTHENTICATION_BACKENDS
contiene lo siguiente:
('django.contrib.auth.backends.ModelBackend',)
Ese es el esquema básico de autentificación que verifica la base de datos de usuarios de Django.
El orden de AUTHENTICATION_BACKENDS
se tiene en cuenta, por lo que si el
mismo usuario y contraseña son válidos en múltiples back-ends, Django detendrá
el procesamiento en la primera coincidencia positiva.
16.2.2. Escribir un back-end de autentificación
Un back-end de autentificación es un clase que implementa dos métodos:
get_user(id)
y authenticate(**credentials)
.
El método get_user
recibe un id
— el cual podría ser un nombre de
usuario, un ID de la base de datos o cualquier cosa — y devuelve un objeto
User
.
El método authenticate
recibe credenciales como argumentos de palabras
clave. La mayoría de las veces se parece a esto:
class MyBackend(object):
def authenticate(self, username=None, password=None):
# Check the username/password and return a User.
Pero podría tambien autentificar un token, como se muestra a continuación:
class MyBackend(object):
def authenticate(self, token=None):
# Check the token and return a User.
De cualquier manera, authenticate
debe verificar las credenciales que
recibe, y debe retornar un objeto User
que coincide con esas credenciales,
si las credenciales son válidas. Si no son válidas, debe retornar None
.
El sistema de administración de Django esta altamente acoplado a su propio
objeto User
respaldado por base de datos descrito en el Capítulo 12. La
mejor manera de lidiar con esto es crear un objeto User
de Django para cada
usuario que existe en tu back-end (ej., en tu directorio LDAP, tu base de datos
SQL externa, etc.). De cualquier manera puedes escribir un script para hacer
esto por adelantado o tu método de autentificación puede hacerlo la primera vez
que el usuario ingresa al sistema.
Aquí está un ejemplo de back-end que autentifica contra unas variables de
usuario y contraseña definidas en tu archivo settings.py
y crea un objeto
User
de Django la primera vez que un usuario se autentifica:
from django.conf import settings
from django.contrib.auth.models import User, check_password
class SettingsBackend(object):
"""
Authenticate against the settings ADMIN_LOGIN and ADMIN_PASSWORD.
Use the login name, and a hash of the password. For example:
ADMIN_LOGIN = 'admin'
ADMIN_PASSWORD = 'sha1$4e987$afbcf42e21bd417fb71db8c66b321e9fc33051de'
"""
def authenticate(self, username=None, password=None):
login_valid = (settings.ADMIN_LOGIN == username)
pwd_valid = check_password(password, settings.ADMIN_PASSWORD)
if login_valid and pwd_valid:
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
# Create a new user. Note that we can set password
# to anything, because it won't be checked; the password
# from settings.py will.
user = User(username=username, password='get from settings.py')
user.is_staff = True
user.is_superuser = True
user.save()
return user
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None