[Django学习] 用户身份验证模块
django 用户身份验证模块(/django/contrib/auth/__init__.py)
在 settings.py 中,可以通过 AUTHENTICATION_BACKENDS 指定多个验证后台;
默认的一个后台是 django.contrib.auth.backends.ModelBackend
验证身份时,遇到第一个验证成功的就返回。
authenticate 方法
=============================================
对指定的用户名/密码或其他身份凭据(用 kwargs 方式指定的,因此可扩展)进行验证,
成功返回 user,失败返回 None.
如果验证成功,authenticate 方法还会给返回的 user 对象添加 backend 属性,指示是哪个配置的后台代码验证成功。
login 方法:
==============================================
向 session 中添加 user.id, user.backend 两个值。
logout 方法:
==============================================
去除上述两个值。
get_user 方法
==============================================
先取出 session 中的已登录的用户的 userid, backend 信息,
然后根据 backend 路径加载相关 backend 模块,
调用 backend 的 get_user 方法获取用户。
以上流程如果失败,则返回一个 AnonymousUser.
一般的用户登录代码:
那么 auth 这个包的 get_user 方法在什么地方用到呢,查了一下代码,发现在
/django/contrib/auth/middleware.py
这里给 request 注入了一个 user 属性,为了避免多次加载时反复调用 backend 的后台代码去数据库中读取用户,这里实现了一个 lazy-load 模式,用的是 __class__ 和 __get__ 结合的办法,很值得学习。我不清楚这个实现手段准确的叫法在 python 中是什么,大体是运行时通过修改类,去修改相关类实例的行为,这也是 python 动态性的优势的一个体现。
这样,我们在使用 request.user 的时候,就有内建的缓存机制了。
有时候,我们希望自动登录一个指定的用户,而这时候不知道用户的密码(密码可能是 hash 存储的)。但是默认的 authenticate 方法必须有 password 传递进去,其执行结果是给 user 对象赋了一个 backend 属性,为此我写了一个方法来模拟这个功能,实现不知道密码的情况下登录指定用户:
这里所需的 user 参数我们可以直接通过某些其他的键值从数据库取得,比如 email 或者 id.
在 settings.py 中,可以通过 AUTHENTICATION_BACKENDS 指定多个验证后台;
默认的一个后台是 django.contrib.auth.backends.ModelBackend
验证身份时,遇到第一个验证成功的就返回。
authenticate 方法
=============================================
对指定的用户名/密码或其他身份凭据(用 kwargs 方式指定的,因此可扩展)进行验证,
成功返回 user,失败返回 None.
如果验证成功,authenticate 方法还会给返回的 user 对象添加 backend 属性,指示是哪个配置的后台代码验证成功。
login 方法:
==============================================
向 session 中添加 user.id, user.backend 两个值。
logout 方法:
==============================================
去除上述两个值。
get_user 方法
==============================================
先取出 session 中的已登录的用户的 userid, backend 信息,
然后根据 backend 路径加载相关 backend 模块,
调用 backend 的 get_user 方法获取用户。
以上流程如果失败,则返回一个 AnonymousUser.
一般的用户登录代码:
from django.contrib.auth import authenticate, login
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
那么 auth 这个包的 get_user 方法在什么地方用到呢,查了一下代码,发现在
/django/contrib/auth/middleware.py
class LazyUser(object):
def __get__(self, request, obj_type=None):
if not hasattr(request, '_cached_user'):
from django.contrib.auth import get_user
request._cached_user = get_user(request)
return request._cached_user
class AuthenticationMiddleware(object):
def process_request(self, request):
assert hasattr(request, 'session'), "The Django authentication middleware requires session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.sessions.middleware.SessionMiddleware'."
request.__class__.user = LazyUser()
return None
def __get__(self, request, obj_type=None):
if not hasattr(request, '_cached_user'):
from django.contrib.auth import get_user
request._cached_user = get_user(request)
return request._cached_user
class AuthenticationMiddleware(object):
def process_request(self, request):
assert hasattr(request, 'session'), "The Django authentication middleware requires session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.sessions.middleware.SessionMiddleware'."
request.__class__.user = LazyUser()
return None
这里给 request 注入了一个 user 属性,为了避免多次加载时反复调用 backend 的后台代码去数据库中读取用户,这里实现了一个 lazy-load 模式,用的是 __class__ 和 __get__ 结合的办法,很值得学习。我不清楚这个实现手段准确的叫法在 python 中是什么,大体是运行时通过修改类,去修改相关类实例的行为,这也是 python 动态性的优势的一个体现。
这样,我们在使用 request.user 的时候,就有内建的缓存机制了。
有时候,我们希望自动登录一个指定的用户,而这时候不知道用户的密码(密码可能是 hash 存储的)。但是默认的 authenticate 方法必须有 password 传递进去,其执行结果是给 user 对象赋了一个 backend 属性,为此我写了一个方法来模拟这个功能,实现不知道密码的情况下登录指定用户:
def login_user(request, user):
user.backend = 'django.contrib.auth.backends.ModelBackend'
from django.contrib.auth import login
login(request, user)
user.backend = 'django.contrib.auth.backends.ModelBackend'
from django.contrib.auth import login
login(request, user)
这里所需的 user 参数我们可以直接通过某些其他的键值从数据库取得,比如 email 或者 id.