[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.

一般的用户登录代码:

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)


那么 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

这里给 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 参数我们可以直接通过某些其他的键值从数据库取得,比如 email 或者 id.

posted on 2007-04-23 15:25  NeilChen  阅读(2603)  评论(1编辑  收藏  举报

导航