============================= Django中的用户认证 ============================= :作者: 马踏飞燕 :联系: honeyday.mj@gmail.com :版本: 0.9 :主页: http://honeyday.org :版权: FDL .. contents:: 目录 .. section-numbering:: Django自带了一个用户授权认证系统。 它可以处理用户帐户、组、权限和基于cookie的用户会话。 本篇文档将解释它是如何工作的。 概 览 ======== 认证系统包括: * 用户(Users) * 权限(Permissions): 二进制 (yes/no) 的标志,用来指明用户都能做哪些事情。 * 组(Groups): 向多个用户应用标签和权限的通用方法。 * 消息(Messages): 为给定的用户排队消息的一个简单的方法。 安 装 ======== 认证支持作为Django的一个应用被绑定在 ``django.contrib.auth`` 中。 安装方法如下: 1. 把 ``'django.contrib.auth'`` 放到你的 ``INSTALLED_APPS`` 设置中。 2. 运行命令 ``manage.py syncdb`` 。 注意,默认情况下,通过使用 ``django-admin.py startproject`` 来创建的工程已经在 ``settings.py`` 中的 ``INSTALLED_APPS`` 包含了 ``'django.contrib.auth'`` 。 如果你的 ``INSTALLED_APPS`` 中已经包含了 ``'django.contrib.auth'`` ,你也可以再次 运行 ``manage.py syncdb`` 。你可以随意运行多少次都无所谓,每一次它都仅仅安装需要 的部分。 ``syncdb`` 创建必要的数据表,同时也为已经安装的apps创建他们需要用到的权限对象。 当你第一次运行这个命令的时候,它还会提示你创建一个超级用户的帐户。 当你做完以上这些步骤之后,认证系统就安装好了。 用户(Users) =========== 用户(Users) 表现为一个标准的Django模型,他在 `django/contrib/auth/models.py`_ 中。 .. _django/contrib/auth/models.py: http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/models.py API 参考 -------- 字 段 ~~~~~~ ``User`` 对象包含如下字段: * ``username`` -- 必须。小于等于30个字符。(字母、数字和下划线) * ``first_name`` -- 可选。小于等于30个字符。 * ``last_name`` -- 可选。小于等于30个字符。 * ``email`` -- 可选。电子邮件地址。Optional. E-mail address. * ``password`` -- 必须。密码的hash值。(Django不保存原始密码。) 原始密码可以是任意长的并且可以包含任意字符。请看下面的 “密码” 节。 * ``is_staff`` -- 布尔型。标识用户能否访问admin界面。 * ``is_active`` -- 布尔型。标识用户能否登录到admin界面。如果不想删除用户 请把它设为 ``False`` * ``is_superuser`` -- 布尔型。标识用户可以得到所有的权限。 * ``last_login`` -- 用户上一次登录的日期时间。默认设置为当前的日期和时间。 * ``date_joined`` -- 用户帐户创建的日期。默认设置为帐户创建时的日期和时间。 方 法 ~~~~~~ ``User`` 对象有2个多对多(many-to-many)的字段: ``groups`` 和 ``user_permissions`` 。 ``User`` 对象可以像其他Django对象(`Django model`_)那样访问他们关联的对象。 :: myuser.objects.groups = [group_list] myuser.objects.groups.add(group, group,...) myuser.objects.groups.remove(group, group,...) myuser.objects.groups.clear() myuser.objects.permissions = [permission_list] myuser.objects.permissions.add(permission, permission, ...) myuser.objects.permissions.remove(permission, permission, ...] myuser.objects.permissions.clear() 除了这些自动生成的API方法外, ``User`` 对象还有如下的自定义的方法: * ``is_anonymous()`` -- 总是返回 ``False`` 。这是区别 ``User`` and ``AnonymousUser`` 对象的一个方法。通常你应该使用 ``is_authenticated()`` 而不是这个方法。 * ``is_authenticated()`` -- 总是返回 ``True`` 。这是测试用户是否被认证了。 * ``get_full_name()`` -- 返回 ``first_name`` 加 ``last_name``, 中间用空格隔开。 * ``set_password(raw_password)`` -- 用给定的字符串设定用户密码,并且 处理密码的hash值。不保存 ``User`` 对象。 * ``check_password(raw_password)`` -- 如果给定的用户密码是正确的,那么返回 ``True`` 。 (通过比较密码的hash值来实现的。) * ``get_group_permissions()`` -- 返回从用户所在的组里面获取的权限列表。 * ``get_all_permissions()`` -- 返回用户拥有的所有的权限。包括组权限和用户权限。 * ``has_perm(perm)`` -- 当参数的格式为 ``"package.codename"`` 的时候,并且 用户拥有特殊权限的时候,返回 ``True`` 。 * ``has_perms(perm_list)`` -- 同上。用户对列表中每一个参数都有特殊权限的时候。 每一个参数的格式都是 ``"package.codename"`` 。 * ``has_module_perms(package_name)`` -- 当用户对给定的包(Django app label)有权限的时候返回 ``True`` 。 * ``get_and_delete_messages()`` -- 返回用户对列中的 ``Message`` 对象列表并且从对列中删除 ``Message`` 对象。 * ``email_user(subject, message, from_email=None)`` -- 向用户发送e-mail。 如果 ``from_email`` 是 ``None``, Django 使用 `DEFAULT_FROM_EMAIL`_ 设置。 * ``get_profile()`` -- 返回站点特定的用户档案。 如果当前站点不允许查询档案的话,Django将抛出 ``django.contrib.auth.models.SiteProfileNotAvailable`` 异常。 .. _Django model: http://www.djangoproject.com/documentation/model_api/ .. _DEFAULT_FROM_EMAIL: http://www.djangoproject.com/documentation/settings/#default-from-email 管理功能 ~~~~~~~~ ``User`` 模型有一个自定义的管理器,它有如下的函数: * ``create_user(username, email, password)`` -- 创建,保存并返回一个 ``User`` 。 ``username``, ``email`` 和 ``password`` 被设置为给定的值,并且 ``User`` 设置了 ``is_active=True`` 。 请看下面的 _`创建用户` 中的例子。 * ``make_random_password(length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789')`` 返回一个给定长度的并且是包含给定字符的随机密码。(注意: ``allowed_chars`` 的默认值 不包括 ``"I"`` 或者类似的字符,这是为了避免字符分辨不清而产生的抱怨。) 基本用法 -------- 创建用户 ~~~~~~~~ 创建用户最基本的方法就是使用Django提供的 ``create_user`` 函数:: >>> from django.contrib.auth.models import User >>> user = User.objects.create_user('john', 'lennon@thebeatles.com', 'johnpassword') # 在这里,User对象已经可以保存到数据库中了。 # 你还可以改变它的其它属性。 >>> user.is_staff = True >>> user.save() 更改密码 ~~~~~~~~ 使用 ``set_password()`` 更改密码:: >>> from django.contrib.auth.models import User >>> u = User.objects.get(username__exact='john') >>> u.set_password('new password') >>> u.save() 除非你很清楚的知道你在做什么,否则不要直接设置 ``password`` 属性。 这将在下一节中阐释。 密码 ---- ``User`` 的 ``password`` 属性是一个如下格式的字符串:: hashtype$salt$hash 它们是 hashtype, salt 和 hash, 用一个美元符号来分隔的。 Hashtype是 ``sha1`` (默认) 或 ``md5`` -- 单向加密的方法。Salt 是一个随机字符串用来为密码的原文创建hash。 例如:: sha1$a1976$a36cc8cbf81742a8fb52e221aaeab48ed7f58ab4 ``User.set_password()`` 和 ``User.check_password()`` 函数负责处理设置和检测这些密码。 在Django先前的版本中, 例如 0.90, 仅使用MD5而不使用salt。 为了向后兼容,这些依然被支持。他们会在第一次使用 ``check_password()`` 来成功检测用户密码的时候自动将其 转换为新的格式。 匿名用户 --------------- ``django.contrib.auth.models.AnonymousUser`` 是一个类,它实现了 ``django.contrib.auth.models.User`` 接口, 有如下的不同点: * ``id`` 总是 ``None``. * ``is_anonymous()`` 返回 ``True`` 而不是 ``False``. * ``is_authenticated()`` 返回 ``False`` 而不是 ``True``. * ``has_perm()`` 总是返回 ``False``. * ``set_password()``, ``check_password()``, ``save()``, ``delete()``, ``set_groups()`` and ``set_permissions()`` 抛出 ``NotImplementedError`` 异常. 在实际应用中,你可能并不需要 ``AnonymousUser`` 对象。 但是他们被应用到网络请求(Web request)中,这将在下面的章节中讲述。 创建超级用户 ------------------- 在你将 ``'django.contrib.auth'`` 添加到 ``INSTALLED_APPS`` 中之后,并且第一次 运行 ``manage.py syncdb`` 命令时,它将提示你创建一个超级用户。 但是如果你需要在之后的操作过程中用命令行创建超级用户的话,你可以使用 ``create_superuser.py`` 。 命令如下:: python /path/to/django/contrib/auth/create_superuser.py 请确认你已经将 ``/path/to/`` 加入到PYTHON_PATH中。 Web请求中的认证 ============================== 到目前为止,本文档已经介绍了操作认证相关的对象的低级的API。 在高一级上,Django可以将认证框架挂接到它本身系统的请求对象(`request objects`_)中。 首先,安装 ``SessionMiddleware`` 和 ``AuthenticationMiddleware`` 中间件。 把他们加入到 ``MIDDLEWARE_CLASSES`` 设置中即可。 更多信息请看 `session documentation`_ 。 当你安装好这些中间件之后,你就可以在视图(view)中访问 ``request.user`` 了。 ``request.user`` 将返回当前登录的用户的一个 ``User`` 对象。 如果当前没有用户登录,那么 ``request.user`` 将返回一个 ``AnonymousUser`` 对象的实例。 你可以通过 ``is_authenticated()`` 来判断是否有用户登录,如下: if request.user.is_authenticated(): # 认证的用户 else: # 匿名用户 .. _request objects: http://www.djangoproject.com/documentation/request_response/#httprequest-objects .. _session documentation: http://www.djangoproject.com/documentation/sessions/ 如何登录一个用户 -------------------- Django 在 ``django.contrib.auth`` 提供了2个函数: ``authenticate()`` 和 ``login()`` 。 如果通过给定的用户名和密码做认证,请使用 ``authenticate()`` 函数。 他接收2个参数,一个是 ``username`` 一个是 ``password`` 。 如果认证成功,它返回一个 ``User`` 对象。 如果密码无效,它返回一个 ``None`` 。 例如:: from django.contrib.auth import authenticate user = authenticate(username='john', password='secret') if user is not None: print "用户名、密码正确!" else: print "用户名、密码错误!" 在视图中登录一个用户的话,使用 ``login()`` 函数。 它接收 ``HttpRequest`` 对象和一个 ``User`` 对象。 ``login()`` 通过Django的session框架把用户的ID保存到session中。 所以,你要确认你已经安装了session中间件。 下面是合用 ``authenticate()`` 和 ``login()`` 的例子:: from django.contrib.auth import authenticate, login def my_view(request): username = request.POST['username'] password = request.POST['password'] user = authenticate(username=username, password=password) if user is not None: login(request, user) # 转到成功页面 else: # 返回错误信息 如何登出用户 --------------------- 要登出使用 ``django.contrib.auth.login()`` 登录的用户的话,可以在视图中使用 ``django.contrib.auth.logout()`` 。 它接收一个 ``HttpRequest`` 参数,没有返回值。 例如:: from django.contrib.auth import logout def logout_view(request): logout(request) # 转到成功页面 请注意:如果用户没有登录的话, ``logout()`` 也不会抛出任何异常的。 限制已登录用户的访问 ---------------------------------- 原始的方法 ~~~~~~~~~~~ 最简单、最原始的限制页面访问的方法是在每个页面上加入 ``request.user.is_authenticated()`` 并且把它重定向到登录页面。 :: from django.http import HttpResponseRedirect def my_view(request): if not request.user.is_authenticated(): return HttpResponseRedirect('/login/?next=%s' % request.path) #... 或者显示一条出错信息 :: def my_view(request): if not request.user.is_authenticated(): return render_to_response('myapp/login_error.html') #... login_required 修饰符 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 你可以使用 ``login_required`` 修饰符来作为一个快捷方式 :: from django.contrib.auth.decorators import login_required def my_view(request): # ... my_view = login_required(my_view) 下面是一个等价的例子,使用了Python 2.4的decorator样式 :: from django.contrib.auth.decorators import login_required @login_required def my_view(request): # ... ``login_required`` 作下面这些事情: * 如果用户没有登录,那么重定向到 ``/accounts/login/`` ,传入当前的绝对URL路径作为 query string ``next`` 的值。例如: ``/accounts/login/?next=/polls/3/`` 。 * 如果用户已经登录了,那么就正常执行view的代码。 请注意,你需要映射正确的处理登录用的视图(view)到 ``/accounts/login/`` 。 把下面的行加入到你的URLconf中:: (r'^accounts/login/$', 'django.contrib.auth.views.login'), ``django.contrib.auth.views.login`` 的作用是:: * 如果通过 ``GET`` 方式调用的话, 它显示一个登录表单并通过POST的方式登录。 * 如果通过 ``POST`` 方式调用的话,它试图把用户登录进去。 如果登录成功, 视图(view)重定向到 ``/accounts/profile/`` (目前是硬性编码的,就是写死的。)。 如果登录失败,则继续显示登录表单。 你需要自己提供一个登录表单的模版,默认叫 ``registration/login.html`` 。 这个模版需要获得3个模版上下文的变量: * ``form``: 一个 ``FormWrapper`` 对象,用来显示登录表单。 更多请看``FormWrapper`` 对象的 `forms documentation`_ 。 * ``next``: 登录成功后重定向的URL。也可能包含一个查询字符串。 * ``site_name``: 当前 ``Site`` 的名字。根据 ``SITE_ID`` 设置的信息获取。 参考 `site framework docs`_ 。 如果你不想使用 ``registration/login.html`` 这个模版,你可以为在URLconf中的视图(view)传入 一个 ``template_name`` 作为扩展的参数。 :: (r'^accounts/login/$', 'django.contrib.auth.views.login', {'template_name': 'myapp/login.html'}), 下面是一个 ``registration/login.html`` 的例子,你可以以它为基础来开始你的工作。 它扩展自 ``base.html`` 并且定义了一个 ``content`` 块:: {% extends "base.html" %} {% block content %} {% if form.has_errors %} <p>用户名和密码不匹配。请重试。</p> {% endif %} <form method="post" action="."> <table> <tr><td><label for="id_username">用户名:</label></td><td>{{ form.username }}</td></tr> <tr><td><label for="id_password">密码:</label></td><td>{{ form.password }}</td></tr> </table> <input type="submit" value="登录" /> <input type="hidden" name="next" value="{{ next }}" /> </form> {% endblock %} .. _forms documentation: http://www.djangoproject.com/documentation/forms/ .. _site framework docs: http://www.djangoproject.com/documentation/sites/ 已登录用户通过通行测试(pass test)来限制访问 --------------------------------------------------- 为了实现基于特定的权限或其他的测试的访问限制,你应该做同上一节一样的基本事情。 To limit access based on certain permissions or some other test, you'd do essentially the same thing as described in the previous section. 简单的方法是在view中直接运行测试 ``request.user`` 的代码。 例如,这个view检测并确认用户已经登陆并且拥有 ``polls.can_vote`` 的权限。 :: def my_view(request): if not (request.user.is_authenticated() and request.user.has_perm('polls.can_vote')): return HttpResponse("你不能投票。") # ... 你可以使用 ``user_passes_test`` 作为快捷方式 :: from django.contrib.auth.decorators import user_passes_test def my_view(request): # ... my_view = user_passes_test(lambda u: u.has_perm('polls.can_vote'))(my_view) Python 2.4的写法 :: from django.contrib.auth.decorators import user_passes_test @user_passes_test(lambda u: u.has_perm('polls.can_vote')) def my_view(request): # ... ``user_passes_test()`` 需要一个必须的参数: 一个包含 ``User`` 的可调用的对象,如果 用户被允许察看这个页面的话,返回 ``True`` 。 注意,如果 ``User`` 不是匿名的话, ``user_passes_test`` 并不自动监测。 ``user_passes_test()`` 需要一个可选的 ``login_url`` 参数, 它可以让你指定登录表单 的URL(默认是 ``/accounts/login/`` )。 例子,Python 2.3写法 :: from django.contrib.auth.decorators import user_passes_test def my_view(request): # ... my_view = user_passes_test(lambda u: u.has_perm('polls.can_vote'), login_url='/login/')(my_view) 例子,Python 2.4写法 :: from django.contrib.auth.decorators import user_passes_test @user_passes_test(lambda u: u.has_perm('polls.can_vote'), login_url='/login/') def my_view(request): # ... 限制访问 generic views ----------------------- 为了限制访问 `generic view`_, 可以为view写一个包装器,并且在URLconf中指定为它。 例如 :: from django.views.generic.date_based import object_detail @login_required def limited_object_detail(*args, **kwargs): return object_detail(*args, **kwargs) .. _generic view: http://www.djangoproject.com/documentation/generic_views/ 权限(Permissions) ================= Django自带了一个简单的权限系统。它为向用户和用户组付权限提供了一个途径。 它被用在了Django的admin站点中,当然你也可以把它用在自己的代码中。 Django的admin站点是这样应用权限的: * 通过"add"权限来控制用户是否可以访问添加表单并添加一个指定类型的对象。 * 通过"change"权限来控制用户是否可以访问指定类型对象的列表和修改表单。 * 通过"delete"权限来控制用户是否可以删除指定类型的对象。 权限被赋予每种类型的对象,而不是对象的特定的实例。 你可以说“玛丽可以修改新的故事(stories)”,但是你不能说“玛丽可以修改她创建的新的故事”或者 “玛丽只能修改特定状态的、特定发布时间的、特定ID的故事等等”。 这些功能目前Django的开发人员还在讨论之中。 默认权限 -------- 3个基本的权限 -- 添加(add),创建(create)和删除(delete) -- 在创建包含有 ``class Admin`` 的Django模型的时候都自动被创建好了。 在表面现象的后面,当你运行 ``manage.py syncdb`` 的时候,这些权限被添加到了 ``auth_permission`` 数据表中。 请注意,如果你的模型里没有 ``class Admin`` 的话,当你运行 ``manage.py syncdb`` 的时候 这些权限不会被创建出来。如果你初始化数据库之后还想添加这些权限,可以在模型中加入 ``class Admin`` 然后再运行一次 ``manage.py syncdb`` 。 自定义权限 ---------- 为了给指定的模型自定义权限,可以使用 ``权限(permissions)`` 的 `model Meta attribute`_ 。 这个例子创建了3个自定义的权限 :: class USCitizen(models.Model): # ... class Meta: permissions = ( ("can_drive", "Can drive"), ("can_vote", "Can vote in elections"), ("can_drink", "Can drink alcohol"), ) 接下来的事情就是运行 ``syncdb`` 来创建这些权限。 .. _model Meta attribute: http://www.djangoproject.com/documentation/model_api/#meta-options API参考 ------- 就像用户对象,权限也是实现自Django的模型 `django/contrib/auth/models.py`_. .. _django/contrib/auth/models.py: http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/models.py 字段 ~~~~~~ ``Permission`` 有如下这些字段: * ``name`` -- 必须。小于等于50个字符。例如: ``'Can vote'`` 。 * ``content_type`` -- 必须。 引用自 ``django_content_type`` 数据表, 它包含了已经安装的Django模型的类型。 * ``codename`` -- 必须。小于等于100个字符。例如: ``'can_vote'`` 。 方法 ~~~~~~~ ``Permission`` 有着与其它 `Django model`_ 一样的数据访问方法。 模板中的认证数据 ================ 如果你使用 ``RequestContext`` 的话,已经登录的用户的user和权限对象就保存在 `template context`_ 。 .. admonition:: 技术细节 在技术上,只有当你使用 ``RequestContext`` 的时候 *并且* 你的 ``TEMPLATE_CONTEXT_PROCESSORS`` 设置包含 ``"django.core.context_processors.auth"`` 的时候,这个变量才是有效的。 更多参见 `RequestContext docs`_. .. _RequestContext docs: http://www.djangoproject.com/documentation/templates_python/#subclassing-context-requestcontext 用户(Users) ----------- 当前登录的用户,不管是否是匿名的,存储在模版变量 ``{{ user }}`` 中。 :: {% if user.is_authenticated %} <p>欢迎, {{ user.username }}。谢谢您的来访。</p> {% else %} <p>欢迎,请登录。</p> {% endif %} 权限(Permissions) ----------------- 当前登录用户的权限存储在模版变量 ``{{ perms }}`` 中。 他是 ``django.core.context_processors.PermWrapper`` 的实例。 在 ``{{ perms }}`` 对象中,单个属性的查找是使用 ``User.has_module_perms`` 的。 下面这个例子中,如果用户对 ``foo`` 这个app有任何权限的话,它就返回True。 :: {{ perms.foo }} 二级属性查找是使用 ``User.has_perm`` 。 下面这个例子中,如果用户有 ``foo.can_vote`` 权限的话,它就返回True。 :: {{ perms.foo.can_vote }} 因此,你可以在模板中用 ``{% if %}`` 语句来判断权限 :: {% if perms.foo %} <p>你有操作foo的权限。</p> {% if perms.foo.can_vote %} <p>你可以投票。</p> {% endif %} {% if perms.foo.can_drive %} <p>你可以开车。</p> {% endif %} {% else %} <p>你没有操作foo的权限。</p> {% endif %} .. _template context: http://www.djangoproject.com/documentation/templates_python/ 组(Groups) ========== 组通常用来归类用户,这样你就可以为这些组里面的用户应用权限或者贴其他的标签。 一个用户可以属于任意数量的组。 组中的用户自动获得赋予组的权限。 例如,如果组 ``Site editors`` 有 ``can_edit_home_page`` 的权限, 那么任何加入这个组的用户都自动拥有这个权限。 组也是归类用户并给他们贴标签或扩展功能的一个方便的途径。 例如,你创建一个 ``'Special users'`` 的组,你可以写代码来让他们访问网站的会员专区 或者发送给他们会员专用的电子邮件。 消息(Messages) ============== 消息系统是为给定用户排队消息的轻量级的途径。 一个消息关联到一个 ``User`` 对象。没有过期标志和时间戳。 Django的admin站点用它来发送成功操作后的消息。 例如, ``"poll成功被创建。"`` 就是一条消息。 API很简单 :: * 创建消息用 ``user_obj.message_set.create(message='message_text')`` 。 * 检索/删除消息用 ``user_obj.get_and_delete_messages()``, 他返回用户消息队列(如果有的话)中的一个 ``Message`` 列表,并且从队列中删除这些消息。 下面的例子中,用户创建一个播放列表之后系统把消息保存下来 :: def create_playlist(request, songs): # 用给定的歌曲创建一个播放列表 # ... request.user.message_set.create(message="播放列表添加成功。") return render_to_response("playlists/create.html", context_instance=RequestContext(request)) 如果你使用 ``RequestContext`` ,当前用户和他的消息保存在 `template context`_ 的模版变量 ``{{ messages }}`` 里。 下面是在模板中显示消息的例子 :: {% if messages %} <ul> {% for message in messages %} <li>{{ message.message }}</li> {% endfor %} </ul> {% endif %} 注意, ``RequestContext`` 调用 ``get_and_delete_messages`` 。 所以,就算你不显示他们的话,他们也会被删除的。 最后,请注意这个消息框架仅适用于在用户数据库中的用户。如果要向匿名用户发送消息的话, 请使用 `session framework`_ 。 .. _session framework: http://www.djangoproject.com/documentation/sessions/ 其他认证资源 ============ Django自带的认证系统对于大多数情况来说已经足够用了,但是你也可能需要使用其他的认证源。 其他的用户名和密码或者认证方法等。 例如,你的公司可能已经有了LDAP,并且已经存储了每一位雇员的用户名和密码。 如果你让网络管理员和用户在LDAP和基于Django的应用上使用不同的登录帐户的话,他们会 非常不高兴的。 所以,为了解决这个问题,Django的认证系统允许你插入其他的认证源。 你可以重载Django默认的数据库结构,或者你可以把默认的系统和其他的系统串联起来。 指定认证后端 ------------ 在暗中,Django维护一个"authentication backends"的列表用来测试认证。 当某人调用 ``django.contrib.auth.authenticate()`` -- 上面提到的"如何登录一个用户" -- Django将尝试所有的认证后端。 如果第一个认证方法失败了,Django将会继续尝试第二个,直到所有的都被尝试过。 认证后端的列表在 ``AUTHENTICATION_BACKENDS`` 设置。 内容应该是包含Python路径的元组。 默认情况下, ``AUTHENTICATION_BACKENDS`` 设置为 :: ('django.contrib.auth.backends.ModelBackend',) 这是检测Django用户数据库的基本认证方案。 按照 ``AUTHENTICATION_BACKENDS`` 的排列顺序, 如果同样的用户名和密码在第一次就匹配了,那么Django将停止处理后面的东西。 编写一个认证后端 ---------------- 一个认证后端是一个类,实现了2个方法: ``get_user(id)`` 和 ``authenticate(**credentials)`` 。 ``get_user`` 方法接受一个 ``id`` -- 可以是用户名,数据库ID或者其他的什么 -- 并且返回一个 ``User`` 对象。 ``authenticate`` 方法接受字典型认证信息的参数。大多情况下是如下样子的 :: class MyBackend: def authenticate(username=None, password=None): # 检测用户名和密码,并返回一个User。 他也可以处理一个代号(token),像这样 :: class MyBackend: def authenticate(token=None): # 检测并返回User。 当 ``authenticate`` 接受的参数被验证为有效的时候,应该返回一个 ``User`` 对象; 如果无效的时候,应该返回 ``None`` 。 在本文当开头提到,Django的admin系统紧密地与 ``User`` 对象绑定在一起。 目前,最好的处理方法就是为你每一个现存的后端(例如,你的LDAP目录或者你的外部SQL数据库等等。) 数据创建一个Django的 ``User`` 对象。 你可以预先写一个脚本来做这些事情,或者在用户第一次登录的时候在你的 ``authenticate`` 方法中做这些事情。 下面是一个例子,使用在 ``settings.py`` 文件里定义的用户名和密码 并且在用户第一次登录的时候创建一个Django的 ``User`` 对象。 :: from django.conf import settings from django.contrib.auth.models import User, check_password class SettingsBackend: """ 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: # 创建新用户。 # 我们可以设置任何新的密码,因为它不会被检测。 # 在这里我们使用"get from settings.py"。 user = User(username=username, password='get from settings.py