Django 亮點:用戶模型和身份驗證(第 1 部分)
已發表: 2022-03-10有兩種類型的網站:靜態和動態。 Django 是一個開發動態網站的框架。 雖然靜態網站是一個僅提供信息的網站,但沒有任何交互(除了簡單的頁面請求)會註冊到服務器。 在靜態網站中,服務器將 HTML、CSS 和 JavaScript 發送到客戶端,僅此而已。 更多功能需要動態網站,其中服務器存儲信息並響應用戶交互,而不僅僅是提供頁面。 開發動態站點的一個主要原因是對用戶進行身份驗證並限制內容。
編寫、部署和管理靜態網站比動態網站更容易、更便宜、更安全。 因此,僅當您的項目需要動態範例的附加功能時,您才應該創建一個動態網站。 Django 使用其內置組件簡化並簡化了創建動態站點的過程。 作為動態 Web 應用程序的主要組件之一,“用戶帳戶”對象,如輪子,很容易重新發明,但標準形狀適用於大多數用途。 Django 提供了一個強大的開箱即用的用戶模型,在本文中,我們將介紹提供安全、直觀的用戶身份驗證流程的最佳方式。
系列中的其他部分:
- Django 亮點:模板化保存行(第 2 部分)
- Django 亮點:模型、管理和利用關係數據庫(第 3 部分)
- Django 亮點:處理靜態資產和媒體文件(第 4 部分)
開始設置
如果您想創建自己的 Django 應用程序來試驗本文中的概念,您可以創建一個目錄(最好是虛擬環境),然後運行以下命令:
pip install django django-admin startproject PROJECTNAME cd PROJECTNAME python manage.py startapp APPNAME python manage.py migrate python manage.py runserver
如果您正在尋找創建您的第一個 Django 項目的演練,Django 自己的網站提供了一個很好的。 在本文中,我們沒有使用示例項目,但所討論的概念將適用於幾乎所有 Django 應用程序。
標準用戶模型
從根本上說,用戶帳戶的概念存在兩個原因:訪問控制和個性化應用程序狀態。 訪問控制是指系統上的資源僅對某些用戶可用。 個性化狀態很大程度上取決於應用程序的用途,但可能包括設置、數據或任何其他特定於單個用戶的記錄。 Django stock User
模型為這兩個用例提供了合理的方法。
最初,Django 應用程序中有兩種類型的用戶:超級用戶帳戶和普通用戶。 超級用戶擁有普通帳戶的所有屬性和權限,還可以訪問 Django 管理面板,這是一個強大的應用程序,我們將在以後的文章中詳細探討。 本質上,超級用戶可以創建、編輯或刪除應用程序中的任何數據,包括其他用戶帳戶。
從根本上說,用戶帳戶的概念存在兩個原因:訪問控制和個性化應用程序狀態。
“
要在您自己的 Django 應用程序上創建超級用戶,請運行:
python manage.py createsuperuser
用戶帳戶的另一個好處是將個性化數據存儲到數據庫中。 默認情況下,Django 只需要用戶名和密碼,但提供可選字段供用戶輸入他們的名字、姓氏和電子郵件地址。 您可以在 Django 網站上閱讀完整的模型參考。 我們將在下面討論擴展這個模型。
安全性和可靠性
Django 在用戶模型中包含大量的密碼管理中間件。 用戶密碼必須至少為 8 個字符,不能全部為數字,不能與用戶名匹配太近,並且不在 20,000 個最常用密碼的列表中。 Django 庫存表格驗證了這些要求。 當密碼發送到服務器時,它會在存儲之前進行加密,默認情況下使用帶有 SHA256 哈希的 PBKDF2 算法。 總體而言,默認密碼系統無需開發人員的任何努力即可提供強大的安全性。 除非您有特定的專業知識和令人信服的理由來更改應用程序中處理密碼的方式,否則不要修改此行為。
另一個方便的內置功能是要求用戶名是唯一的。 如果您考慮一下,如果有兩個用戶名為“djangofan1”的用戶,並且服務器收到該用戶名的登錄請求,它就不會知道哪個用戶正在嘗試訪問該應用程序。 對他們來說不幸的是,第二個嘗試註冊“djangofan1”的用戶將不得不選擇一個不同的名稱,也許是“djangofan2”。 這種唯一性約束在數據庫級別強制執行,但再次由 Django 提供的表單驗證。
最後,關於刪除用戶的說明。 雖然刪除用戶是可能的,但大多數複雜的應用程序都會有許多資源與每個用戶帳戶相關聯。 如果您想在不刪除那些附加對象的情況下有效地刪除用戶,請將用戶的is_active
字段設置為 false。 然後,那些其他資源仍然與帳戶相關聯,而不是被自己刪除,並且超級用戶可以隨時重新激活用戶帳戶。 請注意,這不會釋放用戶名,但將帳戶設置為非活動狀態以及將用戶名更改為隨機的唯一值可以達到相同的效果。 最後,如果您的站點政策或適用的當地法律要求用戶帳戶是完全可刪除的,那麼is_active
方法是不夠的。
除非您有特定的專業知識和令人信服的理由來更改應用程序中處理密碼的方式,否則不要修改此行為。
“
標準使用
當您想註冊一個新的用戶帳戶時,這樣做的視圖可能類似於views.py中的以下內容:
from django.shortcuts import render, redirect from django.contrib.auth import authenticate, login from django.contrib.auth.forms import UserCreationForm def signup(request): if request.user.is_authenticated: return redirect('/') if request.method == 'POST': form = UserCreationForm(request.POST) if form.is_valid(): form.save() username = form.cleaned_data.get('username') password = form.cleaned_data.get('password1') user = authenticate(username=username, password=password) login(request, user) return redirect('/') else: return render(request, 'signup.html', {'form': form}) else: form = UserCreationForm() return render(request, 'signup.html', {'form': form})
讓我們分解一下:
- 如果用戶已經登錄,我們會將他們從註冊頁面重定向。
- 如果請求方式是POST,則表示創建用戶的表單已經填寫完畢,可以創建用戶了。
- 首先,使用用戶提供的數據在後端構造表單對象。
- 如果表單有效,則創建用戶並登錄,然後將其發送到主頁。
- 否則,將它們轉儲回用戶創建頁面,並提供有關哪些數據無效的信息(例如,它們請求的用戶名已在使用中)。
- 否則,用戶是第一次訪問該頁面,應該會看到創建新帳戶的表單。
現在檢查帳戶登錄:
from django.shortcuts import render, redirect from django.contrib.auth import authenticate, login from django.contrib.auth.forms import AuthenticationForm def signin(request): if request.user.is_authenticated: return render(request, 'homepage.html') if request.method == 'POST': username = request.POST['username'] password = request.POST['password'] user = authenticate(request, username=username, password=password) if user is not None: login(request, user) return redirect('/') else: form = AuthenticationForm(request.POST) return render(request, 'signin.html', {'form': form}) else: form = AuthenticationForm() return render(request, 'signin.html', {'form': form})
另一個細分:
- 如果用戶已經登錄,我們會將他們從登錄頁面重定向。
- 如果請求方法是 POST,則表示登錄表單已填寫,是時候對用戶進行帳戶身份驗證了。
- 首先,使用用戶提供的數據對用戶進行身份驗證
- 如果用戶名和密碼對應一個帳戶,則將該用戶登錄
- 否則,將他們帶回登錄頁面並預先填寫表單信息
- 否則,用戶是第一次訪問該頁面,應該會看到用於登錄的表單。
最後,您的用戶可能最終想要退出。 這個請求的基本代碼很簡單:
from django.shortcuts import render, redirect from django.contrib.auth import logout def signout(request): logout(request) return redirect('/')
一旦用戶登錄到他們的帳戶,直到他們在該設備上註銷,他們就擁有了一個“會話”。 在此期間,來自其瀏覽器的後續請求將能夠訪問僅限帳戶的頁面。 一個用戶可以同時激活多個會話。 默認情況下,會話不會超時。
當用戶在其設備上具有活動會話時,他們將註冊為True
以進行request.user.is_authenticated
檢查。 將頁面限制為僅登錄用戶的另一種方法是函數上方的@login_required
裝飾器。 有多種其他方法可以實現相同的目標,詳見此處。
如果此級別的配置超出您的預期,則可以使用更加開箱即用的用戶管理方法。 這些常用的身份驗證視圖為用戶管理提供標準路由、視圖和表單,並且可以通過將它們分配給自定義 URL、傳遞自定義模板甚至子類化視圖來進行修改以進行更多控制。
擴展用戶模型
通常,您需要擴展用戶模型以提供更細粒度的訪問控製或為每個帳戶存儲更多用戶數據。 我們將在下面探討幾種常見情況。
從用戶模型中刪除字段
與本節的標題相反,我實際上不建議直接更改用戶模型或關聯的數據庫模式! 在設置新 Django 項目期間,默認情況下會在您的數據庫中建立通用用戶模型。 默認用戶模型與默認用戶模型密切相關,因此更改它可能會在您的應用程序中產生意想不到的影響(尤其是如果您使用第三方庫),因此不建議添加或刪除字段,而且框架也不容易做到這一點。
默認情況下,用戶唯一需要的兩個字段是用戶名和密碼。 如果您不想使用任何其他字段,只需忽略它們的存在,因為可以創建沒有名字、姓氏或電子郵件地址的用戶。 有一組默認字段,如 last_login 和 date_joined,如果您不想要它們,也可以忽略它們。 如果您有需要從用戶模型中刪除可選字段的實際技術限制,那麼您已經知道它並且不需要本文。
您可能希望在用戶模型中刪除字段的一個常見原因是刪除用戶名以支持電子郵件作為唯一標識符。 在這種情況下,當從表單數據創建用戶或驗證請求時,除了在電子郵件字段中使用之外,只需輸入電子郵件地址作為用戶名。 當用戶名被格式化為電子郵件地址時,用戶名字段仍將強制執行唯一性約束。 字符串是字符串,它們將被同等對待。
與默認用戶模型有太多關聯,因此更改它可能會對您的應用程序產生意想不到的影響,尤其是在您使用第三方庫的情況下。
“
使用配置文件添加字段
同樣,如果您想存儲有關用戶的額外信息,則不應嘗試修改默認用戶模型。 即使對於單個字段,也可以通過與現有用戶的一對一關係定義您自己的對象。 這個額外的模型通常稱為Profile
。 假設您想為每個用戶存儲中間名和出生日期 (dob)。 Profile
將在models.py中定義如下:
from django.db import models from django.contrib.auth.models import User class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) middle_name = models.CharField(max_length=30, blank=True) dob = models.DateField(null=True, blank=True)
自定義訪問控制
您的應用程序可能需要區分不同類型的用戶來訪問信息和功能。 Django 提供了一個用於創建自定義細粒度訪問控制的系統:權限和組。
權限是確定對資源的訪問權限的對象。 一個用戶可以擁有一個或多個權限。 例如,他們可能具有對產品表的讀取權限和對客戶表的寫入權限。 權限的確切實現因應用程序而異,但 Django 的方法可以直觀地定義數據權限並將這些權限分配給用戶。
企業和其他大型組織的應用程序通常實施基於角色的訪問控制。 本質上,一個用戶可以有不同的角色,每個角色都有一定的權限。 Django 實現這種模式的工具是 Group。 一個組可以有任意數量的權限,每個權限可以分配給任意數量的組。 然後,用戶不是直接獲得權限,而是通過他們的組成員資格獲得權限,從而使應用程序更易於管理。
概述:集成支付提供商
集成支付處理器的精確過程因應用程序和提供商而異。 但是,我將籠統地介紹該過程。
外包支付的主要優勢之一是提供商負責存儲和驗證高度監管的數據,例如信用卡信息。 然後,該服務與您的應用程序共享一些唯一的用戶令牌以及有關其支付歷史的數據。 與添加配置文件一樣,您可以創建與核心User
關聯的模型並將數據存儲在該模型中。 與密碼一樣,重要的是要遵循與提供商的給定集成,以避免不正確地存儲敏感信息。
概述:社交登錄
我想簡要介紹的另一個廣泛而復雜的領域是社交登錄。 Facebook 和 Google 等大型平台以及 GitHub 等小型網站都提供 API 以使用其服務對用戶進行身份驗證。 與支付提供商類似,這會在您的數據庫中創建一條記錄,將帳戶鏈接到其數據庫中的帳戶。
您可能希望在您的網站中包含社交身份驗證,以便用戶更輕鬆地註冊,而無需創建一組新的登錄憑據。 如果您的應用程序僅針對已經使用提供社交身份驗證選項的特定網站的客戶,它可能會通過降低進入門檻來幫助您從該市場吸引用戶。 此外,如果您的應用程序打算從第三方服務訪問用戶的數據,則在身份驗證期間鏈接帳戶可以簡化授予權限的過程。
但是,使用社交身份驗證也有缺點。 第三方提供商的 API 更改或中斷可能會中斷您的應用程序的正常運行時間或開發活動。 通常,外部依賴項會增加應用程序的複雜性。 最後,值得考慮您正在與之集成的第三方的數據收集和使用政策,並確保它們符合您和您的用戶的期望。
如果您確實確定社交身份驗證適合您的應用程序,幸運的是,有一個庫可以滿足您的要求。 Python Social Auth for Django 是一個包,用於在 Django 項目中啟用 Python 的社交身份驗證生態系統的功能。
包起來
與用戶帳戶一樣普遍,它的廣泛使用可能導致不必要地解決相同的問題。 希望本文向您展示了 Django 中可用的強大功能的範圍,並讓您了解創建用戶帳戶時應用程序的基本職責。
Django Highlights 是一個介紹 Django 中 Web 開發的重要概念的系列。 每篇文章都是作為 Django 開發方面的獨立指南編寫的,旨在幫助前端開發人員和設計人員更深入地了解代碼庫的“另一半”。 這些文章主要是為了幫助您了解理論和約定,但包含一些代碼示例,這些示例是用 Django 3.0 編寫的。 我們在本文中涉及的幾個概念,包括模板、管理員用戶、模型和表單,將在本系列的後續文章中單獨詳細探討。
系列中的其他部分:
- Django 亮點:模板化保存行(第 2 部分)
- Django 亮點:模型、管理和利用關係數據庫(第 3 部分)
- Django 亮點:處理靜態資產和媒體文件(第 4 部分)