用戶&Authentication

Django 用戶認(rèn)證系統(tǒng)處理用戶帳號(hào),組,權(quán)限以及基于cookie的用戶會(huì)話。 這個(gè)系統(tǒng)一般被稱為 auth/auth (認(rèn)證與授權(quán))系統(tǒng)。 這個(gè)系統(tǒng)的名稱同時(shí)也表明了用戶常見的兩步處理。

  • 驗(yàn)證 (認(rèn)證) 用戶是否是他所宣稱的用戶(一般通過查詢數(shù)據(jù)庫驗(yàn)證其用戶名和密碼)

  • 驗(yàn)證用戶是否擁有執(zhí)行某種操作的 授權(quán) (通常會(huì)通過檢查一個(gè)權(quán)限表來確認(rèn))

根據(jù)這些需求,Django 認(rèn)證/授權(quán) 系統(tǒng)會(huì)包含以下的部分:

  • 用戶 : 在網(wǎng)站注冊(cè)的人

  • 權(quán)限 : 用于標(biāo)識(shí)用戶是否可以執(zhí)行某種操作的二進(jìn)制(yes/no)標(biāo)志

  • 組 :一種可以將標(biāo)記和權(quán)限應(yīng)用于多個(gè)用戶的常用方法

  • Messages : 向用戶顯示隊(duì)列式的系統(tǒng)消息的常用方法

打開認(rèn)證支持


  • 將 'django.contrib.auth' 放在你的 INSTALLED_APPS 設(shè)置中,然后運(yùn)行 manage.py syncdb以創(chuàng)建對(duì)應(yīng)的數(shù)據(jù)庫表。

  • 確認(rèn) SessionMiddleware 后面的 MIDDLEWARE_CLASSES 設(shè)置中包含 'django.contrib.auth.middleware.AuthenticationMiddleware' SessionMiddleware。

使用User對(duì)象


通過以上步驟,我們就可以在視圖(view)的函數(shù)中處理user了。 在視圖中存取users,主要用 request.user ;這個(gè)對(duì)象表示當(dāng)前已登錄的用戶。 如果用戶還沒登錄,這就是一個(gè)AnonymousUser對(duì)象(細(xì)節(jié)見下)。你可以很容易地通過 is_authenticated() 方法來判斷一個(gè)用戶是否已經(jīng)登錄了:

if request.user.is_authenticated():
    # Do something for authenticated users.
else:
    # Do something for anonymous users.
  • User屬性

password 必需的。 密碼的哈希值(Django不儲(chǔ)存原始密碼)。
is_staff 布爾值。 用戶是否擁有網(wǎng)站的管理權(quán)限。
is_active 布爾值。 設(shè)置該賬戶是否可以登錄,把該標(biāo)志位置為False而不是直接刪除賬戶。
is_superuser 布爾值 標(biāo)識(shí)用戶是否擁有所有權(quán)限,無需顯式地權(quán)限分配定義。
last_login 用戶上次登錄的時(shí)間日期。 它被默認(rèn)設(shè)置為當(dāng)前的日期/時(shí)間。
date_joined 賬號(hào)被創(chuàng)建的日期時(shí)間 當(dāng)賬號(hào)被創(chuàng)建時(shí),它被默認(rèn)設(shè)置為當(dāng)前的日期/時(shí)間。

  • User關(guān)聯(lián)對(duì)象

User 對(duì)象有兩個(gè)many-to-many屬性。 groupspermissions 。正如其他的many-to-many屬性使用的方法一樣,User 對(duì)象可以獲得它們相關(guān)的對(duì)象:

# Set a user's groups:
myuser.groups = group_list

# Add a user to some groups:
myuser.groups.add(group1, group2,...)

# Remove a user from some groups:
myuser.groups.remove(group1, group2,...)

# Remove a user from all groups:
myuser.groups.clear()

# Permissions work the same way
myuser.permissions = permission_list
myuser.permissions.add(permission1, permission2, ...)
myuser.permissions.remove(permission1, permission2, ...)
myuser.permissions.clear()

登錄&登出

from django.contrib import auth

def login_view(request):
    username = request.POST.get('username', '')
    password = request.POST.get('password', '')
    user = auth.authenticate(username=username, password=password)
    if user is not None and user.is_active:
        # Correct password, and the user is marked "active"
        auth.login(request, user)
        # Redirect to a success page.
        return HttpResponseRedirect("/account/loggedin/")
    else:
        # Show an error page
        return HttpResponseRedirect("/account/invalid/")


from django.contrib import auth

def logout_view(request):
    auth.logout(request)
    # Redirect to a success page.
    return HttpResponseRedirect("/account/loggedout/")

在實(shí)際中,你一般不需要自己寫登錄/登出的函數(shù);認(rèn)證系統(tǒng)提供了一系例視圖用來處理登錄和登出。 使用認(rèn)證視圖的第一步是把它們寫在你的URLconf中。

from django.contrib.auth.views import login, logout

urlpatterns = patterns('',
    # existing patterns here...
    (r'^accounts/login/$',  login),
    (r'^accounts/logout/$', logout),
)
#/accounts/login/ 和 /accounts/logout/ 是Django提供的視圖的默認(rèn)URL

如果用戶登錄成功,缺省會(huì)重定向到 /accounts/profile 。 你可以提供一個(gè)保存登錄后重定向URL的next隱藏域來重載它的行為。
logout視圖有一些不同。 默認(rèn)情況下它渲染 registration/logged_out.html 模板,視圖中還可以包含一個(gè)參數(shù) next_page 用于退出后重定向。

訪問限制

檢查 request.user.is_authenticated() ,然后重定向到登陸頁面:

from django.http import HttpResponseRedirect

def my_view(request):
    if not request.user.is_authenticated():
        return HttpResponseRedirect('/accounts/login/?next=%s' % request.path)

或者顯示一個(gè)出錯(cuò)信息:

def my_view(request):
    if not request.user.is_authenticated():
        return render_to_response('myapp/login_error.html')


使用便捷的 login_required 修飾符:

from django.contrib.auth.decorators import login_required

@login_required
def my_view(request):

login_required 做下面的事情:

  • 用戶沒有登錄, 重定向到 /accounts/login/ , 把當(dāng)前絕對(duì)URL作為 next 在查詢字符串中傳遞過去, 例如: /accounts/login/?next=/polls/3/

  • 如果用戶已經(jīng)登錄, 正常地執(zhí)行視圖函數(shù)

對(duì)通過測(cè)試的用戶限制訪問

def vote(request):
    if request.user.is_authenticated() and request.user.has_perm('polls.can_vote')):
        # vote here
    else:
        return HttpResponse("You can't vote in this poll.")

#Django有一個(gè)稱為 user_passes_test 的簡潔方式。它接受參數(shù)然后為你指定的情況生成裝飾器。

def user_can_vote(user):
    return user.is_authenticated() and user.has_perm("polls.can_vote")

@user_passes_test(user_can_vote, login_url="/login/")
def vote(request):
    # Code here can assume a logged-in user with the correct permission.
  • user_passes_test 使用一個(gè)必需的參數(shù): 一個(gè)可調(diào)用的方法,當(dāng)存在 User 對(duì)象并當(dāng)此用戶允許查看該頁面時(shí)返回 True 。user_passes_test 不會(huì)自動(dòng)檢查 User
    是否認(rèn)證,你應(yīng)該自己做這件事。
  • 第二個(gè)可選的參數(shù) login_url ,它讓你指定你的登錄頁面的URL(默認(rèn)為 /accounts/login/ )。 如果用戶沒有通過測(cè)試,那么user_passes_test將把用戶重定向到login_url

Django為這種情形提供了一個(gè)捷徑: permission_required() 裝飾器。 使用這個(gè)裝飾器,前面的例子可以改寫為:

from django.contrib.auth.decorators import permission_required

@permission_required('polls.can_vote', login_url="/login/")
def vote(request):
    # ...
  • permission_required() 也有一個(gè)可選的 login_url 參數(shù), 這個(gè)參數(shù)默認(rèn)為 '/accounts/login/'

限制通用視圖的訪問

在Django用戶郵件列表中問到最多的問題是關(guān)于對(duì)通用視圖的限制性訪問。 為實(shí)現(xiàn)這個(gè)功能,你需要自己包裝視圖,并且在URLconf中,將你自己的版本替換通用視圖:

from django.contrib.auth.decorators import login_required
from django.views.generic.date_based import object_detail

@login_required
def limited_object_detail(*args, **kwargs):
    return object_detail(*args, **kwargs)

當(dāng)然, 你可以用任何其他限定修飾符來替換 login_required 。

管理 Users, Permissions 和 Groups

當(dāng)你需要絕對(duì)的控制權(quán)的時(shí)候,低層 API 需要深入專研,我們將在下面的章節(jié)中討論它們。

創(chuàng)建用戶

使用 create_user 輔助函數(shù)創(chuàng)建用戶:

>>> from django.contrib.auth.models import User
>>> user = User.objects.create_user(username='john',
...                                 email='jlennon@beatles.com',
...                                 password='glass onion')
>>> user.is_staff = True
>>> user.save()
修改密碼

你可以使用 set_password() 來修改密碼:

>>> user = User.objects.get(username='john')
>>> user.set_password('goo goo goo joob')
>>> user.save()
處理注冊(cè)

每個(gè)開發(fā)人員都希望實(shí)現(xiàn)各自不同的注冊(cè)方法,所以Django把寫注冊(cè)視圖的工作留給了你,作為這個(gè)事情的最簡化處理, 我們可以提供一個(gè)小視圖, 提示一些必須的用戶信息并創(chuàng)建這些用戶。 Django為此提供了可用的內(nèi)置表單, 下面這個(gè)例子就使用了這個(gè)表單:

from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response

def register(request):
    if request.method == 'POST':
        form = UserCreationForm(request.POST)
        if form.is_valid():
            new_user = form.save()
            return HttpResponseRedirect("/books/")
    else:
        form = UserCreationForm()
    return render_to_response("registration/register.html", {
        'form': form,
    })

這個(gè)表單需要一個(gè)叫 registration/register.html 的模板。這個(gè)模板可能是這樣的:

{% extends "base.html" %}

{% block title %}Create an account{% endblock %}

{% block content %}
  <h1>Create an account</h1>

  <form action="" method="post">
      {{ form.as_p }}
      <input type="submit" value="Create the account">
  </form>
{% endblock %}
在模板中使用認(rèn)證數(shù)據(jù)

當(dāng)前登入的用戶以及他(她)的權(quán)限可以通過 RequestContext 在模板的context中使用。從技術(shù)上來說,只有當(dāng)

  • 使用了 RequestContext這些變量才可用。
  • TEMPLATE_CONTEXT_PROCESSORS 設(shè)置包含了 “django.core.context_processors.auth” (默認(rèn)情況就是如此

這些變量才能在模板context中使用。
當(dāng)使用 RequestContext 時(shí), 當(dāng)前用戶 (是一個(gè) User 實(shí)例或一個(gè) AnonymousUser 實(shí)例) 存儲(chǔ)在模板變量 {{ user }} 中:

{% if user.is_authenticated %}
  <p>Welcome, {{ user.username }}. Thanks for logging in.</p>
{% else %}
  <p>Welcome, new user. Please log in.</p>
{% endif %}

這些用戶的權(quán)限信息存儲(chǔ)在 {{ perms }} 模板變量中。

你有兩種方式來使用 perms 對(duì)象。 你可以使用類似于 {{ perms.polls }} 的形式來檢查,對(duì)于某個(gè)特定的應(yīng)用,一個(gè)用戶是否具有 任意 權(quán)限;你也可以使用 {{ perms.polls.can_vote }} 這樣的形式,來檢查一個(gè)用戶是否擁有特定的權(quán)限。

{% if perms.polls %}
  <p>You have permission to do something in the polls app.</p>
  {% if perms.polls.can_vote %}
    <p>You can vote!</p>
  {% endif %}
{% else %}
  <p>You don't have permission to do anything in the polls app.</p>
{% endif %}
權(quán)限、組和消息
權(quán)限

Django的admin站點(diǎn)如下使用權(quán)限:

  • 只有設(shè)置了 add 權(quán)限的用戶才能使用添加表單,添加對(duì)象的視圖。

  • 只有設(shè)置了 change 權(quán)限的用戶才能使用變更列表,變更表格,變更對(duì)象的視圖。

  • 只有設(shè)置了 delete 權(quán)限的用戶才能刪除一個(gè)對(duì)象。

權(quán)限是根據(jù)每一個(gè)類型的對(duì)象而設(shè)置的,并不具體到對(duì)象的特定實(shí)例。 例如,我們可以允許Mary改變新故事,但是目前還不允許設(shè)置Mary只能改變自己創(chuàng)建的新故事,或者根據(jù)給定的狀態(tài),出版日期或者ID號(hào)來選擇權(quán)限。

會(huì)自動(dòng)為每一個(gè)Django模型創(chuàng)建三個(gè)基本權(quán)限:增加、改變和刪除。 當(dāng)你運(yùn)行manage.py syncdb命令時(shí),這些權(quán)限被添加到auth_permission數(shù)據(jù)庫表中。

權(quán)限以 "<app>.<action>_<object_name>" 的形式出現(xiàn)。

權(quán)限也就是Django模型中的*** django.contrib.auth.models*** ,你也可以通過Django的數(shù)據(jù)庫API直接操作權(quán)限。

組提供了一種通用的方式來讓你按照一定的權(quán)限規(guī)則和其他標(biāo)簽將用戶分類。 一個(gè)用戶可以隸屬于任何數(shù)量的組。在一個(gè)組中的用戶自動(dòng)獲得了賦予該組的權(quán)限。 例如, Site editors 組擁有 can_edit_home_page 權(quán)限,任何在該組中的用戶都擁有這個(gè)權(quán)限。

組也可以通過給定一些用戶特殊的標(biāo)記,來擴(kuò)展功能。 例如,你創(chuàng)建了一個(gè) 'Special users' 組,并且允許組中的用戶訪問站點(diǎn)的一些VIP部分,或者發(fā)送VIP的郵件消息。

和用戶管理一樣,admin接口是管理組的最簡單的方法。 然而,組也就是Django模型 django.contrib.auth.models ,因此你可以使用Django的數(shù)據(jù)庫API,在底層訪問這些組。

消息

消息系統(tǒng)會(huì)為給定的用戶接收消息。 每個(gè)消息都和一個(gè) User 相關(guān)聯(lián)。

在每個(gè)成功的操作以后,Django的admin管理接口就會(huì)使用消息機(jī)制。 例如,當(dāng)你創(chuàng)建了一個(gè)對(duì)象,你會(huì)在admin頁面的頂上看到 The object was created successfully 的消息。

你也可以使用相同的API在你自己的應(yīng)用中排隊(duì)接收和顯示消息。 API非常地簡單:

  • 要?jiǎng)?chuàng)建一條新的消息,user.message_set.create(message='message_text') 。

  • 要獲得/刪除消息,使用 user.get_and_delete_messages() ,這會(huì)返回一個(gè) Message 對(duì)象的列表,并且從隊(duì)列中刪除返回的項(xiàng)。

例子視圖中,系統(tǒng)在創(chuàng)建了播放單(playlist)以后,為用戶保存了一條消息。

def create_playlist(request, songs):
    # Create the playlist with the given songs.
    # ...
    request.user.message_set.create(
        message="Your playlist was added successfully."
    )
    return render_to_response("playlists/create.html",
        context_instance=RequestContext(request))

當(dāng)使用 RequestContext ,當(dāng)前登錄的用戶以及他(她)的消息,就會(huì)以模板變量 {{ messages }} 出現(xiàn)在模板`的context中。

{% if messages %}
<ul>
    {% for message in messages %}
    <li>{{ message }}</li>
    {% endfor %}
</ul>
{% endif %}

需要注意的是 RequestContext 會(huì)在后臺(tái)調(diào)用 get_and_delete_messages ,因此即使你沒有顯示它們,它們也會(huì)被刪除掉。這個(gè)消息框架只能服務(wù)于在用戶數(shù)據(jù)庫中存在的用戶。 如果要向匿名用戶發(fā)送消息,請(qǐng)直接使用會(huì)話框架。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容