zoukankan      html  css  js  c++  java
  • django用户认证

    =============================
    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

  • 相关阅读:
    Server requested plaintext password but ‘client plaintext auth’ is disabled
    LDAP目录树中常见的关键字
    LINUX下让一个用户添加进多个组中
    CentOS5.6下samba+ldap+smbldaptools的安装
    解决configure: error: Cannot find pam headers. Please check if your system is ready for pam module development
    解决configure: error: C++ compiler cannot create executables问题
    IE中拖动DOM元素的例子
    请确保此代码文件中定义的类与“inherits”属性匹配,并且该类扩展的基类(例如Page 或UserControl)是正确的。
    DOM中的高级事件处理
    好导网(推荐)
  • 原文地址:https://www.cnblogs.com/liuruichao/p/4005852.html
Copyright © 2011-2022 走看看