使用 Django 身份驗證系統

本文說明 Django 身份驗證系統在其預設配置中的用法。此配置已演變為滿足最常見的專案需求,處理相當廣泛的任務,並仔細實作密碼和權限。對於身份驗證需求與預設值不同的專案,Django 支援廣泛的擴充和自訂身份驗證。

Django 身份驗證同時提供身份驗證和授權,通常稱為身份驗證系統,因為這些功能在某種程度上是耦合的。

User 物件

User 物件是身份驗證系統的核心。它們通常代表與您的網站互動的人員,並用於啟用諸如限制存取、註冊使用者設定檔、將內容與建立者關聯等功能。在 Django 的身份驗證框架中,只有一種使用者類別存在,即 '超級使用者' 或管理員 '員工' 使用者只是設定了特殊屬性的使用者物件,而不是不同的使用者物件類別。

預設使用者的主要屬性為

請參閱完整 API 文件以取得完整參考,以下文件更偏向任務導向。

建立使用者

建立使用者最直接的方式是使用內含的 create_user() 輔助函式

>>> from django.contrib.auth.models import User
>>> user = User.objects.create_user("john", "lennon@thebeatles.com", "johnpassword")

# At this point, user is a User object that has already been saved
# to the database. You can continue to change its attributes
# if you want to change other fields.
>>> user.last_name = "Lennon"
>>> user.save()

如果您已安裝 Django 管理介面,也可以互動式建立使用者

建立超級使用者

使用 createsuperuser 命令建立超級使用者

$ python manage.py createsuperuser --username=joe --email=joe@example.com
...\> py manage.py createsuperuser --username=joe --email=joe@example.com

系統會提示您輸入密碼。輸入密碼後,使用者會立即建立。如果您省略 --username--email 選項,系統會提示您輸入這些值。

變更密碼

Django 不會將原始 (明文) 密碼儲存在使用者模型上,只會儲存雜湊值 (請參閱密碼管理方式的文件以取得完整詳細資料)。因此,請勿嘗試直接操作使用者的密碼屬性。這就是為什麼在建立使用者時使用輔助函式的原因。

若要變更使用者的密碼,您有幾個選項

manage.py changepassword *username* 提供從命令列變更使用者密碼的方法。它會提示您變更給定使用者的密碼,您必須輸入兩次。如果兩者相符,則會立即變更新密碼。如果您未提供使用者,則命令會嘗試變更使用者名稱與目前系統使用者相符的密碼。

您也可以使用 set_password() 以程式方式變更密碼

>>> from django.contrib.auth.models import User
>>> u = User.objects.get(username="john")
>>> u.set_password("new password")
>>> u.save()

如果您已安裝 Django 管理介面,也可以在身份驗證系統的管理頁面上變更使用者的密碼。

Django 也提供 檢視表單,可用於允許使用者變更自己的密碼。

變更使用者的密碼將會登出他們的所有工作階段。請參閱密碼變更時的工作階段失效以取得詳細資料。

驗證使用者身份

authenticate(request=None, **credentials)[來源]
aauthenticate(request=None, **credentials)

非同步版本aauthenticate()

使用 authenticate() 來驗證一組憑證。它將憑證作為關鍵字引數,預設情況下為 usernamepassword,針對每個身份驗證後端檢查它們,如果憑證對後端有效,則傳回 User 物件。如果憑證對任何後端無效,或後端引發 PermissionDenied,則傳回 None。例如

from django.contrib.auth import authenticate

user = authenticate(username="john", password="secret")
if user is not None:
    # A backend authenticated the credentials
    ...
else:
    # No backend authenticated the credentials
    ...

request 是可選的 HttpRequest,其會傳遞給身份驗證後端的 authenticate() 方法。

注意

這是驗證一組憑證的低階方式;例如,它是由 RemoteUserMiddleware 使用的。除非您正在撰寫自己的身份驗證系統,否則您可能不會使用此功能。相反地,如果您正在尋找登入使用者的方式,請使用 LoginView

在 Django 5.0 中變更

新增了 aauthenticate() 函式。

權限和授權

Django 隨附內建的權限系統。它提供了一種將權限指派給特定使用者和使用者群組的方式。

它由 Django 管理介面使用,但您可以在自己的程式碼中使用它。

Django 管理介面依下列方式使用權限

  • 物件的檢視存取權限僅限於具有該類型物件「檢視」或「變更」權限的使用者。

  • 檢視「新增」表單和新增物件的存取權限僅限於具有該類型物件「新增」權限的使用者。

  • 檢視變更清單、檢視「變更」表單和變更物件的存取權限僅限於具有該類型物件「變更」權限的使用者。

  • 刪除物件的存取權限僅限於具有該類型物件「刪除」權限的使用者。

權限不僅可以針對物件類型設定,還可以針對特定的物件實例設定。透過使用 has_view_permission()has_add_permission()has_change_permission()has_delete_permission() 方法(這些方法由 ModelAdmin 類別提供),可以針對相同類型的不同物件實例自訂權限。

User 物件有兩個多對多欄位:groupsuser_permissionsUser 物件可以像任何其他 Django 模型 一樣存取其相關物件。

myuser.groups.set([group_list])
myuser.groups.add(group, group, ...)
myuser.groups.remove(group, group, ...)
myuser.groups.clear()
myuser.user_permissions.set([permission_list])
myuser.user_permissions.add(permission, permission, ...)
myuser.user_permissions.remove(permission, permission, ...)
myuser.user_permissions.clear()

預設權限

django.contrib.auth 列在您的 INSTALLED_APPS 設定中時,它會確保為您已安裝的應用程式中定義的每個 Django 模型建立四個預設權限 – 新增、變更、刪除和檢視。

當您執行 manage.py migrate 時,將會建立這些權限;在將 django.contrib.auth 新增到 INSTALLED_APPS 後,第一次執行 migrate 時,將為所有先前安裝的模型以及當時正在安裝的任何新模型建立預設權限。之後,每次執行 manage.py migrate 時,都會為新模型建立預設權限(建立權限的函式已連線到 post_migrate 訊號)。

假設您有一個應用程式,其 app_labelfoo,且有一個名為 Bar 的模型,要測試基本權限,您應該使用

  • 新增:user.has_perm('foo.add_bar')

  • 變更:user.has_perm('foo.change_bar')

  • 刪除:user.has_perm('foo.delete_bar')

  • 檢視:user.has_perm('foo.view_bar')

Permission 模型很少被直接存取。

群組

django.contrib.auth.models.Group 模型是一種對使用者進行分類的通用方式,以便您可以將權限或其他標籤套用到這些使用者。一個使用者可以屬於任意數量的群組。

群組中的使用者會自動擁有授予該群組的權限。例如,如果群組 Site editors 具有權限 can_edit_home_page,則該群組中的任何使用者都將具有該權限。

除了權限之外,群組也是對使用者進行分類以給予他們某些標籤或擴展功能的便捷方式。例如,您可以建立一個群組 'Special users',並且您可以編寫程式碼,例如,讓他們存取您網站的僅限會員部分,或向他們發送僅限會員的電子郵件訊息。

以程式設計方式建立權限

雖然可以在模型的 Meta 類別中定義自訂權限,但您也可以直接建立權限。例如,您可以在 myapp 中為 BlogPost 模型建立 can_publish 權限

from myapp.models import BlogPost
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType

content_type = ContentType.objects.get_for_model(BlogPost)
permission = Permission.objects.create(
    codename="can_publish",
    name="Can Publish Posts",
    content_type=content_type,
)

然後,可以透過 user_permissions 屬性將權限指派給 User,或透過其 permissions 屬性指派給 Group

Proxy 模型需要自己的內容類型

如果您想為 proxy 模型建立權限,請將 for_concrete_model=False 傳遞給 ContentTypeManager.get_for_model() 以取得適當的 ContentType

content_type = ContentType.objects.get_for_model(
    BlogPostProxy, for_concrete_model=False
)

權限快取

ModelBackend 在第一次需要取得權限進行權限檢查後,會將權限快取在使用者物件上。這通常適用於請求-回應週期,因為權限通常不會在新增後立即檢查(例如,在管理員中)。如果您正在新增權限並在之後立即檢查權限(例如,在測試或檢視中),最簡單的解決方案是從資料庫重新取得使用者。例如

from django.contrib.auth.models import Permission, User
from django.contrib.contenttypes.models import ContentType
from django.shortcuts import get_object_or_404

from myapp.models import BlogPost


def user_gains_perms(request, user_id):
    user = get_object_or_404(User, pk=user_id)
    # any permission check will cache the current set of permissions
    user.has_perm("myapp.change_blogpost")

    content_type = ContentType.objects.get_for_model(BlogPost)
    permission = Permission.objects.get(
        codename="change_blogpost",
        content_type=content_type,
    )
    user.user_permissions.add(permission)

    # Checking the cached permission set
    user.has_perm("myapp.change_blogpost")  # False

    # Request new instance of User
    # Be aware that user.refresh_from_db() won't clear the cache.
    user = get_object_or_404(User, pk=user_id)

    # Permission cache is repopulated from the database
    user.has_perm("myapp.change_blogpost")  # True

    ...

Proxy 模型

Proxy 模型的工作方式與具體模型完全相同。使用 Proxy 模型自己的內容類型建立權限。Proxy 模型不會繼承它們子類的具體模型的權限。

class Person(models.Model):
    class Meta:
        permissions = [("can_eat_pizzas", "Can eat pizzas")]


class Student(Person):
    class Meta:
        proxy = True
        permissions = [("can_deliver_pizzas", "Can deliver pizzas")]
>>> # Fetch the content type for the proxy model.
>>> content_type = ContentType.objects.get_for_model(Student, for_concrete_model=False)
>>> student_permissions = Permission.objects.filter(content_type=content_type)
>>> [p.codename for p in student_permissions]
['add_student', 'change_student', 'delete_student', 'view_student',
'can_deliver_pizzas']
>>> for permission in student_permissions:
...     user.user_permissions.add(permission)
...
>>> user.has_perm("app.add_person")
False
>>> user.has_perm("app.can_eat_pizzas")
False
>>> user.has_perms(("app.add_student", "app.can_deliver_pizzas"))
True

Web 請求中的驗證

Django 使用 session 和中介軟體將驗證系統掛接到 request 物件

這些在每個請求中提供一個 request.user 屬性和一個 request.auser 異步方法,表示目前使用者。如果目前使用者尚未登入,則此屬性將設定為 AnonymousUser 的實例,否則它將是 User 的實例。

您可以使用 is_authenticated 來區分它們,如下所示

if request.user.is_authenticated:
    # Do something for authenticated users.
    ...
else:
    # Do something for anonymous users.
    ...

或在異步檢視中

user = await request.auser()
if user.is_authenticated:
    # Do something for authenticated users.
    ...
else:
    # Do something for anonymous users.
    ...
在 Django 5.0 中變更

新增了 HttpRequest.auser() 方法。

如何登入使用者

如果您有一個想要附加到目前 Session 的已驗證使用者,則可以使用 login() 函數來完成。

login(request, user, backend=None)[原始碼]
alogin(request, user, backend=None)

異步版本alogin()

要從檢視中登入使用者,請使用 login()。它接受一個 HttpRequest 物件和一個 User 物件。login() 使用 Django 的 Session 架構,將使用者的 ID 儲存在 Session 中。

請注意,在使用者登入後,匿名 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(request, username=username, password=password)
    if user is not None:
        login(request, user)
        # Redirect to a success page.
        ...
    else:
        # Return an 'invalid login' error message.
        ...
在 Django 5.0 中變更

新增了 alogin() 函數。

選擇驗證後端

當使用者登入時,使用者的 ID 和用於驗證的後端會儲存在使用者的 session 中。這允許在未來的請求中使用相同的 驗證後端 來取得使用者的詳細資料。要儲存在 session 中的驗證後端會依以下方式選擇:

  1. 如果提供了可選的 backend 參數,則使用該參數的值。

  2. 如果存在 user.backend 屬性,則使用該屬性的值。這允許配對 authenticate()login()authenticate() 會在其返回的使用者物件上設定 user.backend 屬性。

  3. 如果 AUTHENTICATION_BACKENDS 中只有一個 backend,則使用該 backend

  4. 否則,拋出一個例外。

在情況 1 和 2 中,backend 參數或 user.backend 屬性的值應為點分隔的導入路徑字串(如在 AUTHENTICATION_BACKENDS 中找到的),而不是實際的後端類別。

如何登出使用者

logout(request)[原始碼]
alogout(request)

非同步版本alogout()

要登出透過 django.contrib.auth.login() 登入的使用者,請在您的 view 中使用 django.contrib.auth.logout()。它接收一個 HttpRequest 物件,並且沒有回傳值。範例:

from django.contrib.auth import logout


def logout_view(request):
    logout(request)
    # Redirect to a success page.

請注意,如果使用者未登入,logout() 不會拋出任何錯誤。

當您呼叫 logout() 時,目前請求的 session 資料會被完全清除。所有現有的資料都會被移除。這是為了防止其他人使用相同的網路瀏覽器登入並存取先前使用者的 session 資料。如果您想在登出後立即讓使用者可以使用任何 session 中的資料,請在呼叫 django.contrib.auth.logout() 之後 執行。

在 Django 5.0 中變更

已新增 alogout() 函式。

限制對已登入使用者的存取

原始方法

限制對頁面存取的原始方法是檢查 request.user.is_authenticated,並重新導向到登入頁面

from django.conf import settings
from django.shortcuts import redirect


def my_view(request):
    if not request.user.is_authenticated:
        return redirect(f"{settings.LOGIN_URL}?next={request.path}")
    # ...

...或顯示錯誤訊息

from django.shortcuts import render


def my_view(request):
    if not request.user.is_authenticated:
        return render(request, "myapp/login_error.html")
    # ...

login_required 修飾器

login_required(redirect_field_name='next', login_url=None)[原始碼]

作為一個捷徑,您可以使用方便的 login_required() 修飾器

from django.contrib.auth.decorators import login_required


@login_required
def my_view(request): ...

login_required() 執行以下操作

  • 如果使用者未登入,則重新導向到 settings.LOGIN_URL,並在查詢字串中傳遞目前的絕對路徑。例如:/accounts/login/?next=/polls/3/

  • 如果使用者已登入,則正常執行 view。view 程式碼可以自由假設使用者已登入。

預設情況下,使用者在成功驗證後應重新導向的路徑儲存在名為 "next" 的查詢字串參數中。如果您希望對此參數使用不同的名稱,login_required() 接收一個可選的 redirect_field_name 參數

from django.contrib.auth.decorators import login_required


@login_required(redirect_field_name="my_redirect_field")
def my_view(request): ...

請注意,如果您為 redirect_field_name 提供值,您很可能也需要自訂您的登入範本,因為儲存重新導向路徑的範本上下文變數將使用 redirect_field_name 的值作為其鍵,而不是 "next"(預設值)。

login_required() 也接收一個可選的 login_url 參數。範例:

from django.contrib.auth.decorators import login_required


@login_required(login_url="/accounts/login/")
def my_view(request): ...

請注意,如果您未指定 login_url 參數,您需要確保 settings.LOGIN_URL 和您的登入 view 已正確關聯。例如,使用預設值,將以下程式碼加入您的 URLconf:

from django.contrib.auth import views as auth_views

path("accounts/login/", auth_views.LoginView.as_view()),

settings.LOGIN_URL 也接受 view 函式名稱和 具名 URL 模式。這允許您在 URLconf 中自由地重新對應您的登入 view,而無需更新設定。

注意

login_required 修飾器不會檢查使用者的 is_active 旗標,但預設的 AUTHENTICATION_BACKENDS 會拒絕不活躍的使用者。

另請參閱

如果您正在為 Django 的管理介面編寫自訂 view(或需要與內建 view 使用相同的授權檢查),您可能會發現 django.contrib.admin.views.decorators.staff_member_required() 修飾器是 login_required() 的一個有用的替代方案。

在 Django 5.1 中變更

已新增對包裝非同步 view 函式的支援。

LoginRequiredMixin 混合類別

當使用 基於類別的 view 時,您可以使用 LoginRequiredMixin 來實現與 login_required 相同的行為。這個混合類別應位於繼承列表的最左側位置。

class LoginRequiredMixin[原始碼]

如果 view 使用這個混合類別,所有未經身份驗證的使用者的請求將會被重新導向到登入頁面,或顯示 HTTP 403 禁止錯誤,具體取決於 raise_exception 參數。

您可以設定 AccessMixin 的任何參數來自訂未授權使用者的處理方式

from django.contrib.auth.mixins import LoginRequiredMixin


class MyView(LoginRequiredMixin, View):
    login_url = "/login/"
    redirect_field_name = "redirect_to"

注意

如同 login_required 修飾器一樣,這個混合類別不會檢查使用者的 is_active 旗標,但預設的 AUTHENTICATION_BACKENDS 會拒絕不活躍的使用者。

login_not_required 修飾器

Django 5.1 中的新功能。

當安裝 LoginRequiredMiddleware 時,預設情況下所有 view 都需要驗證。某些 view,例如登入 view,可能需要停用此行為。

login_not_required()[原始碼]

當安裝 LoginRequiredMiddleware 時,允許對此 view 發出未經驗證的請求。

限制對通過測試的已登入使用者的存取

要根據某些權限或其他測試來限制存取,您基本上會執行與前一節所述相同的操作。

您可以直接在 view 中對 request.user 執行您的測試。例如,此 view 會檢查使用者是否在所需的網域中擁有電子郵件,如果沒有,則重新導向到登入頁面

from django.shortcuts import redirect


def my_view(request):
    if not request.user.email.endswith("@example.com"):
        return redirect("/login/?next=%s" % request.path)
    # ...
user_passes_test(test_func, login_url=None, redirect_field_name='next')[原始碼]

作為一個快捷方式,您可以使用方便的 user_passes_test 裝飾器,當可呼叫物件返回 False 時,它會執行重新導向。

from django.contrib.auth.decorators import user_passes_test


def email_check(user):
    return user.email.endswith("@example.com")


@user_passes_test(email_check)
def my_view(request): ...

user_passes_test() 接受一個必要參數:一個可呼叫物件,該物件接受一個 User 物件,如果允許使用者檢視頁面,則返回 True。請注意,user_passes_test() 不會自動檢查 User 是否為匿名使用者。

user_passes_test() 接受兩個可選參數

login_url

允許您指定未通過測試的使用者將被重新導向到的 URL。它可能是登入頁面,如果沒有指定,則預設為 settings.LOGIN_URL

redirect_field_name

login_required() 相同。將其設定為 None 會將其從 URL 中移除,如果您要將未通過測試的使用者重新導向到沒有「下一頁」的非登入頁面,您可能會想要這樣做。

例如

@user_passes_test(email_check, login_url="/login/")
def my_view(request): ...
在 Django 5.1 中變更

新增了對包裝非同步視圖函式和使用非同步測試可呼叫物件的支援。

class UserPassesTestMixin[原始碼]

當使用 基於類別的視圖 時,您可以使用 UserPassesTestMixin 來完成此操作。

test_func()[原始碼]

您必須覆寫類別的 test_func() 方法來提供執行的測試。此外,您可以設定 AccessMixin 的任何參數來自訂未授權使用者的處理方式

from django.contrib.auth.mixins import UserPassesTestMixin


class MyView(UserPassesTestMixin, View):
    def test_func(self):
        return self.request.user.email.endswith("@example.com")
get_test_func()[原始碼]

您也可以覆寫 get_test_func() 方法,讓 mixin 對其檢查使用不同的命名函式(而不是 test_func())。

堆疊 UserPassesTestMixin

由於 UserPassesTestMixin 的實作方式,您無法在繼承清單中堆疊它們。以下操作無效

class TestMixin1(UserPassesTestMixin):
    def test_func(self):
        return self.request.user.email.endswith("@example.com")


class TestMixin2(UserPassesTestMixin):
    def test_func(self):
        return self.request.user.username.startswith("django")


class MyView(TestMixin1, TestMixin2, View): ...

如果 TestMixin1 會呼叫 super() 並將該結果納入考量,TestMixin1 將不再能獨立運作。

permission_required 裝飾器

permission_required(perm, login_url=None, raise_exception=False)[原始碼]

檢查使用者是否具有特定權限是一項相對常見的工作。因此,Django 為此情況提供了一個快捷方式:permission_required() 裝飾器

from django.contrib.auth.decorators import permission_required


@permission_required("polls.add_choice")
def my_view(request): ...

就像 has_perm() 方法一樣,權限名稱採用 "<應用程式標籤>.<權限程式碼名稱>" 的形式(例如,polls.add_choice 用於 polls 應用程式中模型的權限)。

該裝飾器也可以接受權限的可迭代物件,在這種情況下,使用者必須具有所有權限才能存取該視圖。

請注意,permission_required() 也接受一個可選的 login_url 參數

from django.contrib.auth.decorators import permission_required


@permission_required("polls.add_choice", login_url="/loginpage/")
def my_view(request): ...

login_required() 裝飾器一樣,login_url 預設為 settings.LOGIN_URL

如果給定了 raise_exception 參數,裝飾器將引發 PermissionDenied,提示 403 (HTTP Forbidden) 視圖,而不是重新導向到登入頁面。

如果您想使用 raise_exception,但也想讓您的使用者有機會先登入,您可以新增 login_required() 裝飾器

from django.contrib.auth.decorators import login_required, permission_required


@login_required
@permission_required("polls.add_choice", raise_exception=True)
def my_view(request): ...

這也可以避免在 LoginViewredirect_authenticated_user=True 且已登入的使用者不具有所有必要權限時的重新導向迴圈。

在 Django 5.1 中變更

已新增對包裝非同步 view 函式的支援。

PermissionRequiredMixin mixin

要將權限檢查套用到 基於類別的視圖,您可以使用 PermissionRequiredMixin

class PermissionRequiredMixin[原始碼]

這個 mixin,就像 permission_required 裝飾器一樣,檢查存取視圖的使用者是否具有所有給定的權限。您應使用 permission_required 參數指定權限(或權限的可迭代物件)

from django.contrib.auth.mixins import PermissionRequiredMixin


class MyView(PermissionRequiredMixin, View):
    permission_required = "polls.add_choice"
    # Or multiple of permissions:
    permission_required = ["polls.view_choice", "polls.change_choice"]

您可以設定 AccessMixin 的任何參數來自訂未授權使用者的處理方式。

您也可以覆寫這些方法

get_permission_required()[原始碼]

返回 mixin 使用的權限名稱的可迭代物件。預設為 permission_required 屬性,如果需要,則轉換為元組。

has_permission()[原始碼]

返回一個布林值,表示目前使用者是否有權限執行裝飾的視圖。預設情況下,這會返回使用 get_permission_required() 返回的權限清單呼叫 has_perms() 的結果。

在基於類別的視圖中重新導向未授權的請求

為了簡化 基於類別的視圖 中的存取限制處理,可以使用 AccessMixin 來設定當存取被拒絕時視圖的行為。已驗證的使用者會以 HTTP 403 Forbidden 回應拒絕存取。匿名使用者會根據 raise_exception 屬性重新導向到登入頁面或顯示 HTTP 403 Forbidden 回應。

class AccessMixin[原始碼]
login_url

get_login_url() 的預設回傳值。預設為 None,此時 get_login_url() 會回退至 settings.LOGIN_URL

permission_denied_message

get_permission_denied_message() 的預設回傳值。預設為空字串。

redirect_field_name

get_redirect_field_name() 的預設回傳值。預設為 "next"

raise_exception

如果此屬性設定為 True,當條件不符合時,會引發 PermissionDenied 異常。當 False (預設值) 時,匿名使用者會被重新導向至登入頁面。

get_login_url()[原始碼]

回傳未通過測試的使用者將被重新導向的 URL。如果設定了 login_url,則回傳該值,否則回傳 settings.LOGIN_URL

get_permission_denied_message()[原始碼]

raise_exceptionTrue 時,此方法可用於控制傳遞給錯誤處理程序以顯示給使用者的錯誤訊息。預設會回傳 permission_denied_message 屬性。

get_redirect_field_name()[原始碼]

回傳一個查詢參數的名稱,該參數會包含使用者成功登入後應重新導向的 URL。如果您將此設定為 None,則不會新增查詢參數。預設會回傳 redirect_field_name 屬性。

handle_no_permission()[原始碼]

根據 raise_exception 的值,此方法會引發 PermissionDenied 異常,或將使用者重新導向至 login_url,如果設定了 redirect_field_name,則可選擇性地包含該值。

變更密碼時使 Session 失效

如果您的 AUTH_USER_MODEL 繼承自 AbstractBaseUser 或實作自己的 get_session_auth_hash() 方法,已驗證的 Session 將包含此函式回傳的雜湊值。在 AbstractBaseUser 的情況下,這是密碼欄位的 HMAC。Django 會驗證每個請求中 Session 的雜湊值是否與請求期間計算的雜湊值相符。這允許使用者透過變更密碼來登出其所有 Session。

Django 包含的預設密碼變更檢視,PasswordChangeViewdjango.contrib.auth 管理介面中的 user_change_password 檢視,會使用新的密碼雜湊更新 Session,因此變更自己密碼的使用者不會登出自己。如果您有自訂密碼變更檢視,並且希望擁有類似的行為,請使用 update_session_auth_hash() 函式。

update_session_auth_hash(request, user)[原始碼]
aupdate_session_auth_hash(request, user)

非同步版本: aupdate_session_auth_hash()

此函式會取得目前的請求和已更新的使用者物件,並從中衍生新的 Session 雜湊值,並適當地更新 Session 雜湊值。它還會輪換 Session 金鑰,使被竊取的 Session Cookie 失效。

用法範例

from django.contrib.auth import update_session_auth_hash


def password_change(request):
    if request.method == "POST":
        form = PasswordChangeForm(user=request.user, data=request.POST)
        if form.is_valid():
            form.save()
            update_session_auth_hash(request, form.user)
    else:
        ...
在 Django 5.0 中變更

新增了 aupdate_session_auth_hash() 函式。

注意

由於 get_session_auth_hash() 是基於 SECRET_KEY,因此必須輪換秘密金鑰值,以避免在更新您的網站以使用新的秘密金鑰時使現有的 Session 失效。有關詳細資訊,請參閱 SECRET_KEY_FALLBACKS

驗證檢視

Django 提供數個檢視,您可以將其用於處理登入、登出和密碼管理。這些檢視使用 stock auth 表單,但您也可以傳入自己的表單。

Django 沒有為驗證檢視提供預設範本。您應該為要使用的檢視建立自己的範本。範本內容記錄在每個檢視中,請參閱所有驗證檢視

使用檢視

在您的專案中實作這些檢視有不同的方法。最簡單的方法是在您自己的 URLconf 中包含 django.contrib.auth.urls 中提供的 URLconf,例如

urlpatterns = [
    path("accounts/", include("django.contrib.auth.urls")),
]

這將包含以下 URL 模式

accounts/login/ [name='login']
accounts/logout/ [name='logout']
accounts/password_change/ [name='password_change']
accounts/password_change/done/ [name='password_change_done']
accounts/password_reset/ [name='password_reset']
accounts/password_reset/done/ [name='password_reset_done']
accounts/reset/<uidb64>/<token>/ [name='password_reset_confirm']
accounts/reset/done/ [name='password_reset_complete']

這些檢視會提供 URL 名稱,方便您參考。有關使用具名 URL 模式的詳細資訊,請參閱URL 文件

如果您想對 URL 擁有更多控制權,可以在您的 URLconf 中參考特定的檢視

from django.contrib.auth import views as auth_views

urlpatterns = [
    path("change-password/", auth_views.PasswordChangeView.as_view()),
]

這些檢視具有可選參數,可用於變更檢視的行為。例如,如果您想要變更檢視使用的範本名稱,可以提供 template_name 參數。執行此操作的一種方法是在 URLconf 中提供關鍵字引數,這些引數會傳遞到檢視。例如

urlpatterns = [
    path(
        "change-password/",
        auth_views.PasswordChangeView.as_view(template_name="change-password.html"),
    ),
]

所有檢視都是基於類別的,這讓您可以透過子類別輕鬆地自訂它們。

所有驗證檢視

這是 django.contrib.auth 提供的所有檢視的清單。有關實作詳細資訊,請參閱使用檢視

class LoginView[原始碼]

URL 名稱: login

有關使用具名 URL 模式的詳細資訊,請參閱URL 文件

方法和屬性

template_name

用於顯示使用者登入畫面的樣板名稱。預設為 registration/login.html

next_page

登入後要重新導向的 URL。預設為 LOGIN_REDIRECT_URL

redirect_field_name

包含登入後要重新導向 URL 的 GET 欄位名稱。預設為 next。如果傳入指定的 GET 參數,則會覆寫 get_default_redirect_url() URL。

authentication_form

用於驗證的可呼叫物件(通常為表單類別)。預設為 AuthenticationForm

extra_context

一個字典,包含要新增到傳遞給樣板的預設上下文資料的額外資料。

redirect_authenticated_user

一個布林值,用於控制已驗證的使用者訪問登入頁面時,是否會像剛成功登入一樣被重新導向。預設為 False

警告

如果您啟用 redirect_authenticated_user,其他網站可以透過請求您網站上圖片檔案的重新導向 URL 來判斷其訪客是否在您的網站上通過驗證。為避免這種「社交媒體指紋」資訊洩漏,請將所有圖片和您的網站圖示託管在單獨的網域上。

啟用 redirect_authenticated_user 也可能在使用 permission_required() 裝飾器時導致重新導向迴圈,除非使用 raise_exception 參數。

success_url_allowed_hosts

除了 request.get_host() 之外,在登入後可以安全重新導向的主機的 set。預設為一個空的 set

get_default_redirect_url()[原始碼]

傳回登入後要重新導向的 URL。預設實作會解析並傳回 next_page(如果已設定),否則傳回 LOGIN_REDIRECT_URL

以下是 LoginView 的運作方式

  • 如果透過 GET 呼叫,它會顯示一個登入表單,該表單會透過 POST 到相同的 URL。稍後會詳細說明。

  • 如果透過 POST 呼叫並帶有使用者提交的憑證,它會嘗試讓使用者登入。如果登入成功,檢視會重新導向到 next 中指定的 URL。如果未提供 next,則會重新導向到 settings.LOGIN_REDIRECT_URL (預設為 /accounts/profile/)。如果登入不成功,則會重新顯示登入表單。

您有責任為登入樣板提供 HTML,預設名稱為 registration/login.html。此樣板會傳遞四個樣板上下文變數

  • form:代表 AuthenticationFormForm 物件。

  • next:成功登入後要重新導向的 URL。這也可能包含查詢字串。

  • site:根據 SITE_ID 設定的目前 Site。如果您沒有安裝網站框架,這會設定為 RequestSite 的實例,後者會從目前的 HttpRequest 衍生網站名稱和網域。

  • site_namesite.name 的別名。如果您沒有安裝網站框架,這將設定為 request.META['SERVER_NAME'] 的值。有關網站的更多資訊,請參閱「網站」框架

如果您不想將樣板命名為 registration/login.html,您可以透過 URLconf 中 as_view 方法的額外參數傳遞 template_name 參數。例如,此 URLconf 行會改用 myapp/login.html

path("accounts/login/", auth_views.LoginView.as_view(template_name="myapp/login.html")),

您也可以使用 redirect_field_name 指定包含登入後要重新導向 URL 的 GET 欄位名稱。預設情況下,該欄位名為 next

以下是一個您可以作為起點的 registration/login.html 範例樣板。它假設您有一個定義 content 區塊的 base.html 樣板

{% extends "base.html" %}

{% block content %}

{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}

{% if next %}
    {% if user.is_authenticated %}
    <p>Your account doesn't have access to this page. To proceed,
    please login with an account that has access.</p>
    {% else %}
    <p>Please login to see this page.</p>
    {% endif %}
{% endif %}

<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<table>
<tr>
    <td>{{ form.username.label_tag }}</td>
    <td>{{ form.username }}</td>
</tr>
<tr>
    <td>{{ form.password.label_tag }}</td>
    <td>{{ form.password }}</td>
</tr>
</table>

<input type="submit" value="login">
<input type="hidden" name="next" value="{{ next }}">
</form>

{# Assumes you set up the password_reset view in your URLconf #}
<p><a href="{% url 'password_reset' %}">Lost password?</a></p>

{% endblock %}

如果您已自訂驗證(請參閱 自訂驗證),您可以透過設定 authentication_form 屬性來使用自訂驗證表單。此表單必須在其 __init__() 方法中接受 request 關鍵字引數,並提供一個傳回已驗證使用者物件的 get_user() 方法 (此方法僅在表單驗證成功後才會被呼叫)。

class LogoutView[原始碼]

POST 請求時登出使用者。

URL 名稱: logout

屬性

next_page

登出後要重新導向的 URL。預設為 LOGOUT_REDIRECT_URL

template_name

登出使用者後要顯示的樣板完整名稱。預設為 registration/logged_out.html

redirect_field_name

一個 GET 欄位的名稱,其中包含登出後要重新導向的 URL。預設值為 'next'。如果傳遞了指定的 GET 參數,則會覆寫 next_page URL。

extra_context

一個字典,包含要新增到傳遞給樣板的預設上下文資料的額外資料。

success_url_allowed_hosts

除了 request.get_host() 之外,允許在登出後重新導向的安全主機的 set。預設值為空的 set

範本上下文

  • title:本地化的字串「已登出」。

  • site:根據 SITE_ID 設定的目前 Site。如果您沒有安裝網站框架,這會設定為 RequestSite 的實例,後者會從目前的 HttpRequest 衍生網站名稱和網域。

  • site_namesite.name 的別名。如果您沒有安裝網站框架,這將設定為 request.META['SERVER_NAME'] 的值。有關網站的更多資訊,請參閱「網站」框架

logout_then_login(request, login_url=None)[原始碼]

POST 請求上登出使用者,然後重新導向到登入頁面。

URL 名稱: 未提供預設 URL

選用參數

  • login_url:要重新導向到的登入頁面 URL。如果未提供,則預設為 settings.LOGIN_URL

class PasswordChangeView[原始碼]

URL 名稱: password_change

允許使用者變更其密碼。

屬性

template_name

用於顯示密碼變更表單的範本完整名稱。如果未提供,則預設為 registration/password_change_form.html

success_url

成功變更密碼後要重新導向的 URL。預設值為 'password_change_done'

form_class

自訂的「變更密碼」表單,必須接受 user 關鍵字引數。此表單負責實際變更使用者的密碼。預設值為 PasswordChangeForm

extra_context

一個字典,包含要新增到傳遞給樣板的預設上下文資料的額外資料。

範本上下文

  • form:密碼變更表單(請參閱上面的 form_class)。

class PasswordChangeDoneView[原始碼]

URL 名稱: password_change_done

使用者變更密碼後顯示的頁面。

屬性

template_name

要使用的範本完整名稱。如果未提供,則預設為 registration/password_change_done.html

extra_context

一個字典,包含要新增到傳遞給樣板的預設上下文資料的額外資料。

class PasswordResetView[原始碼]

URL 名稱: password_reset

允許使用者透過產生一次性使用連結來重設其密碼,該連結可用於重設密碼,並將該連結傳送至使用者註冊的電子郵件地址。

如果滿足以下條件,此檢視將會傳送電子郵件

  • 系統中存在提供的電子郵件地址。

  • 要求的用戶處於活動狀態(User.is_activeTrue)。

  • 要求的用戶擁有可用的密碼。標記為不可用密碼的使用者(請參閱 set_unusable_password())不允許要求重設密碼,以防止在使用 LDAP 等外部驗證來源時遭到濫用。

如果 滿足這些條件的任何一項,則不會傳送電子郵件,但使用者也不會收到任何錯誤訊息。這可以防止資訊洩漏給潛在的攻擊者。如果要在這種情況下提供錯誤訊息,您可以子類化 PasswordResetForm 並使用 form_class 屬性。

注意

請注意,傳送電子郵件會花費額外時間,因此您可能會因為現有電子郵件地址的重設請求持續時間與不存在電子郵件地址的重設請求持續時間之間的差異,而容易受到電子郵件地址列舉計時攻擊。為了減少開銷,您可以使用允許非同步傳送電子郵件的第三方套件,例如 django-mailer

屬性

template_name

用於顯示密碼重設表單的範本完整名稱。如果未提供,則預設為 registration/password_reset_form.html

form_class

用於取得要重設密碼的使用者電子郵件的表單。預設值為 PasswordResetForm

email_template_name

用於產生帶有重設密碼連結之電子郵件的範本完整名稱。如果未提供,則預設為 registration/password_reset_email.html

subject_template_name

用於帶有重設密碼連結之電子郵件主旨的範本完整名稱。如果未提供,則預設為 registration/password_reset_subject.txt

token_generator

用於檢查一次性連結的類別實例。這將預設為 default_token_generator,它是 django.contrib.auth.tokens.PasswordResetTokenGenerator 的實例。

success_url

成功發出密碼重設請求後要重新導向的 URL。預設值為 'password_reset_done'

from_email

有效的電子郵件地址。依預設,Django 會使用 DEFAULT_FROM_EMAIL

extra_context

一個字典,包含要新增到傳遞給樣板的預設上下文資料的額外資料。

html_email_template_name

用於產生帶有密碼重設連結之 text/html 多部分電子郵件的範本完整名稱。依預設,不會傳送 HTML 電子郵件。

extra_email_context

電子郵件範本中可用的上下文資料字典。它可用於覆寫下列列出的預設範本上下文值,例如 domain

範本上下文

  • form:用於重設使用者密碼的表單(請參閱上面的 form_class)。

電子郵件範本上下文

  • emailuser.email 的別名

  • user:目前的 User,根據 email 表單欄位。只有活動使用者才能重設其密碼(User.is_active is True)。

  • site_namesite.name 的別名。如果您沒有安裝網站框架,這將設定為 request.META['SERVER_NAME'] 的值。有關網站的更多資訊,請參閱「網站」框架

  • domainsite.domain 的別名。如果未安裝網站架構,則此值將設定為 request.get_host() 的值。

  • protocol:http 或 https

  • uid:使用者以 base 64 編碼的主索引鍵。

  • token:用於檢查重設連結是否有效的權杖。

範例 registration/password_reset_email.html(電子郵件內文範本)

Someone asked for password reset for email {{ email }}. Follow the link below:
{{ protocol}}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}

主旨範本使用相同的範本上下文。主旨必須是單行純文字字串。

class PasswordResetDoneView[原始碼]

URL 名稱: password_reset_done

當使用者收到重設密碼連結的電子郵件後,會顯示此頁面。如果 PasswordResetView 沒有設定明確的 success_url URL,則預設會呼叫此檢視。

注意

如果系統中不存在提供的電子郵件地址、使用者處於非啟用狀態,或擁有無法使用的密碼,使用者仍會被重新導向至此檢視,但不會寄送電子郵件。

屬性

template_name

要使用的範本完整名稱。如果未提供,則預設為 registration/password_reset_done.html

extra_context

一個字典,包含要新增到傳遞給樣板的預設上下文資料的額外資料。

class PasswordResetConfirmView[原始碼]

URL 名稱: password_reset_confirm

顯示輸入新密碼的表單。

來自 URL 的關鍵字引數

  • uidb64:以 base 64 編碼的使用者 ID。

  • token:用來檢查密碼是否有效的權杖。

屬性

template_name

用於顯示確認密碼檢視的範本完整名稱。預設值為 registration/password_reset_confirm.html

token_generator

用於檢查密碼的類別實例。預設為 default_token_generator,它是 django.contrib.auth.tokens.PasswordResetTokenGenerator 的實例。

post_reset_login

一個布林值,表示在密碼重設成功後是否應自動驗證使用者身分。預設為 False

post_reset_login_backend

如果 post_reset_loginTrue,則在驗證使用者身分時要使用的驗證後端的虛線路徑。僅當您設定了多個 AUTHENTICATION_BACKENDS 時才需要。預設為 None

form_class

將用於設定密碼的表單。預設為 SetPasswordForm

success_url

密碼重設完成後要重新導向的 URL。預設為 'password_reset_complete'

extra_context

一個字典,包含要新增到傳遞給樣板的預設上下文資料的額外資料。

reset_url_token

顯示為密碼重設 URL 組件的權杖參數。預設為 'set-password'

範本上下文

  • form:用於設定新使用者密碼的表單(請參閱上方的 form_class)。

  • validlink:布林值,如果連結(uidb64token 的組合)有效或尚未被使用,則為 True。

class PasswordResetCompleteView[原始碼]

URL 名稱: password_reset_complete

顯示一個檢視,告知使用者密碼已成功變更。

屬性

template_name

用於顯示檢視的範本完整名稱。預設為 registration/password_reset_complete.html

extra_context

一個字典,包含要新增到傳遞給樣板的預設上下文資料的額外資料。

輔助函數

redirect_to_login(next, login_url=None, redirect_field_name='next')[原始碼]

重新導向至登入頁面,然後在成功登入後回到另一個 URL。

必要引數

  • next:成功登入後要重新導向到的 URL。

選用參數

  • login_url:要重新導向到的登入頁面 URL。如果未提供,則預設為 settings.LOGIN_URL

  • redirect_field_name:包含登入後要重新導向到的 URL 的 GET 欄位名稱。如果傳遞了給定的 GET 參數,則會覆寫 next

內建表單

如果您不想使用內建的檢視,但又希望方便地不必為此功能撰寫表單,則驗證系統會提供數個位於 django.contrib.auth.forms 中的內建表單。

注意

內建的驗證表單對它們所使用的使用者模型做出某些假設。如果您正在使用自訂使用者模型,則可能需要為驗證系統定義自己的表單。如需詳細資訊,請參閱有關將內建驗證表單與自訂使用者模型一起使用的說明文件

class AdminPasswordChangeForm[原始碼]

管理介面中用於變更使用者密碼的表單,包括設定無法使用的密碼的功能,這會阻止使用者使用基於密碼的驗證方式登入。

user 作為第一個位置引數。

在 Django 5.1 中變更

新增了停用(或重新啟用)基於密碼驗證的選項。

class AdminUserCreationForm[原始碼]
Django 5.1.1 中的新功能。

管理介面中用於建立新使用者的表單。繼承自 UserCreationForm

它包含一個額外的 usable_password 欄位,預設為啟用。如果啟用 usable_password,它會驗證 password1password2 是否為非空白且相符,使用 validate_password() 驗證密碼,並使用 set_password() 設定使用者的密碼。如果停用 usable_password,則不會進行密碼驗證,並透過呼叫 set_unusable_password() 來停用使用者的基於密碼驗證方式。

class AuthenticationForm[原始碼]

用於登入使用者的表單。

request 作為其第一個位置引數,並將其儲存在表單實例上供子類別使用。

confirm_login_allowed(user)[原始碼]

預設情況下,AuthenticationForm 會拒絕 is_active 標記設為 False 的使用者。您可以使用自訂策略覆寫此行為,以決定哪些使用者可以登入。方法是使用自訂表單,該表單繼承 AuthenticationForm 並覆寫 confirm_login_allowed() 方法。如果給定的使用者無法登入,此方法應引發 ValidationError

例如,允許所有使用者登入,無論「active」狀態為何

from django.contrib.auth.forms import AuthenticationForm


class AuthenticationFormWithInactiveUsersOkay(AuthenticationForm):
    def confirm_login_allowed(self, user):
        pass

(在這種情況下,您還需要使用允許非使用中用戶的身份驗證後端,例如 AllowAllUsersModelBackend。)

或者只允許某些使用中的使用者登入

class PickyAuthenticationForm(AuthenticationForm):
    def confirm_login_allowed(self, user):
        if not user.is_active:
            raise ValidationError(
                _("This account is inactive."),
                code="inactive",
            )
        if user.username.startswith("b"):
            raise ValidationError(
                _("Sorry, accounts starting with 'b' aren't welcome here."),
                code="no_b_users",
            )
class BaseUserCreationForm[原始碼]

用於建立新使用者的 ModelForm。如果您需要自訂使用者建立表單,這是建議的基礎類別。

它有三個欄位:username(來自使用者模型)、password1password2。它會驗證 password1password2 是否匹配,使用 validate_password() 驗證密碼,並使用 set_password() 設定使用者的密碼。

class PasswordChangeForm[原始碼]

允許使用者變更其密碼的表單。

class PasswordResetForm[原始碼]

用於產生並透過電子郵件傳送一次性使用連結以重設使用者密碼的表單。

send_mail(subject_template_name, email_template_name, context, from_email, to_email, html_email_template_name=None)[原始碼]

使用引數傳送 EmailMultiAlternatives。可以覆寫此方法以自訂電子郵件傳送給使用者的方式。如果您選擇覆寫此方法,請注意處理由於電子郵件傳送失敗而可能引發的例外情況。

參數:
  • subject_template_name – 主旨的範本。

  • email_template_name – 電子郵件內文的範本。

  • context – 傳遞至 subject_templateemail_templatehtml_email_template 的內容(如果它不是 None)。

  • from_email – 寄件者的電子郵件。

  • to_email – 請求者的電子郵件。

  • html_email_template_name – HTML 內文的範本;預設為 None,在這種情況下會傳送純文字電子郵件。

預設情況下,save() 會使用 PasswordResetView 傳遞給其電子郵件內容的相同變數來填入 context

class SetPasswordForm[原始碼]

讓使用者變更其密碼而無需輸入舊密碼的表單。

class UserChangeForm[原始碼]

管理介面中用於變更使用者資訊和權限的表單。

class UserCreationForm[原始碼]

繼承自 BaseUserCreationForm。為了避免與類似的使用者名稱混淆,此表單不允許僅大小寫不同的使用者名稱。

範本中的身份驗證資料

當您使用 RequestContext 時,目前登入的使用者及其權限會在 範本內容 中提供。

技術細節

嚴格來說,只有當您使用 RequestContext 且啟用 'django.contrib.auth.context_processors.auth' 內容處理器時,這些變數才會在範本內容中提供。它位於預設產生的設定檔中。如需更多資訊,請參閱 RequestContext 文件

使用者

當呈現範本 RequestContext 時,目前登入的使用者(User 實例或 AnonymousUser 實例)會儲存在範本變數 {{ user }}

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

如果未使用 RequestContext,則此範本內容變數不可用。

權限

目前登入使用者的權限會儲存在範本變數 {{ perms }} 中。這是 django.contrib.auth.context_processors.PermWrapper 的實例,它是權限的範本友善代理。

{{ perms }} 的單一屬性查閱評估為布林值,是 User.has_module_perms() 的代理。例如,檢查登入的使用者是否在 foo 應用程式中擁有任何權限

{% if perms.foo %}

將雙層屬性查閱評估為布林值,是 User.has_perm() 的代理。例如,檢查登入的使用者是否具有 foo.add_vote 權限

{% if perms.foo.add_vote %}

以下是在範本中檢查權限的更完整範例

{% if perms.foo %}
    <p>You have permission to do something in the foo app.</p>
    {% if perms.foo.add_vote %}
        <p>You can vote!</p>
    {% endif %}
    {% if perms.foo.add_driving %}
        <p>You can drive!</p>
    {% endif %}
{% else %}
    <p>You don't have permission to do anything in the foo app.</p>
{% endif %}

也可以透過 {% if in %} 陳述式查閱權限。例如

{% if 'foo' in perms %}
    {% if 'foo.add_vote' in perms %}
        <p>In lookup works, too.</p>
    {% endif %}
{% endif %}

在管理介面中管理使用者

當您同時安裝 django.contrib.admindjango.contrib.auth 時,管理介面會提供方便的方式來檢視和管理使用者、群組和權限。可以像任何 Django 模型一樣建立和刪除使用者。可以建立群組,並且可以將權限指派給使用者或群組。也會儲存並顯示管理介面中使用者對模型所做的編輯記錄。

建立使用者

您應該會在主要管理索引頁面的「Auth」區段中看到「Users」的連結。「Add user」管理頁面與標準管理頁面不同,它要求您選擇使用者名稱和密碼,然後才能編輯使用者的其他欄位。或者,在此頁面上,您可以選擇使用者名稱並停用該使用者的基於密碼的身份驗證。

另請注意:如果您希望使用者帳戶能夠透過 Django 管理網站建立使用者,您需要給予他們新增使用者變更使用者的權限(即「新增使用者」和「變更使用者」權限)。如果帳戶有新增使用者的權限但沒有變更使用者的權限,則該帳戶將無法新增使用者。為什麼?因為如果您有新增使用者的權限,您就有權建立超級使用者,而超級使用者反過來可以變更其他使用者。因此,Django 需要新增變更權限作為一個輕微的安全措施。

請謹慎考慮您如何允許使用者管理權限。如果您給予非超級使用者編輯使用者的能力,這最終等同於給予他們超級使用者狀態,因為他們將能夠提升包括他們自己在內的使用者的權限!

變更密碼

使用者密碼不會顯示在管理介面中(也不會儲存在資料庫中),但會顯示 密碼儲存詳細資訊。此資訊的顯示中包含一個連結,連至密碼變更表單,該表單允許管理員變更或取消設定使用者密碼。

返回頂部