Django自帶一個用戶認證系統,用於處理用戶帳戶、羣組、許可和基於cookie的用戶會話。css
Django的認證系統包含了身份驗證和權限管理兩部分。簡單地說,身份驗證用於覈實某個用戶是不是合法用戶,權限管理則是決定一個合法用戶具備哪些權限。這裏,「身份驗證」這個詞同時代指上面兩部分的含義。html
系統主要包括:python
相似下面的問題,請使用第三方包:web
默認狀況下,使用django-admin startproject命令後,認證相關的模塊已經自動添加到settings文件內了,若是沒有的話,請手動添加。sql
在 INSTALLED_APPS配置項中:數據庫
在MIDDLEWARE配置項中:django
當配置正確後,運行manage.py migrate命令,建立用戶認證系統相關的數據庫表以及分配預約義的權限。後端
默認的用戶包含下面的屬性:緩存
最直接的辦法是使用 create_user()功能:ruby
>>> from django.contrib.auth.models import User >>> user = User.objects.create_user('john', 'lennon@thebeatles.com', 'johnpassword') # 這時,user是一個User類的實例,已經保存在了數據庫內,你能夠隨時修改它的屬性,例如: >>> user.last_name = 'Lennon' >>> user.save()
若是你已經啓用了Django的admin站點,你也能夠在web頁面上建立用戶。
使用createsuperuser命令
$ python manage.py createsuperuser --username=joe --email=joe@example.com
根據提示輸入名字、密碼和郵箱地址。
Django默認會對密碼進行加密,所以,不要企圖對密碼進行直接操做。這也是爲何要使用一個幫助函數來建立用戶的緣由。
要修改密碼,有兩個辦法:
from django.contrib.auth.models import User u = User.objects.get(username='john') u.set_password('new password') u.save()
一樣能夠在admin中修改密碼。
Django提供了views和forms,方便用戶本身修改密碼。
修改密碼後,用戶的全部當前會話將被註銷。
authenticate(**credentials)[source]:
一般接收username與password做爲參數進行認證。在認證後端中,有一項經過則返回一個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
Django提供了一個權限系統用於它的admin站點,固然你也能夠在你的代碼中使用。
使用方法:
ModelAdmin類提供了 has_add_permission(),has_change_permission()和has_delete_permission()三個方法。User表的對象有兩個多對多的字段,groups和user_permissions,能夠像普通的model同樣訪問他們。
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()
默認狀況下,使用manage.py migrate命令時,Django會給每一個已經存在的model添加默認的權限。
假設你如今有個app叫作foo,有個model叫作bar,使用下面的方式能夠測試默認權限:
add: user.has_perm('foo.add_bar') change: user.has_perm('foo.change_bar') delete: user.has_perm('foo.delete_bar')
Django提供了一個django.contrib.auth.models.Group模型,該model可用於給用戶分組,實現批量管理。用戶和組屬於多對多的關係。用戶自動具備所屬組的全部權限。
例如,你能夠爲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模型的user_permissions屬性或者Group模型的permissions屬性爲用戶添加該權限。
權限檢查後,會被緩存在用戶對象中。參考下面的例子:
from django.contrib.auth.models import Permission, User from django.shortcuts import get_object_or_404 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_bar') permission = Permission.objects.get(codename='change_bar') user.user_permissions.add(permission) # Checking the cached permission set user.has_perm('myapp.change_bar') # 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_bar') # True ...
Django使用session和中間件在請求對象中鉤住認證系統。
每一次請求中都包含一個request.user屬性。若是該用戶未登錄,該屬性的值是AnonymousUser,若是已經登陸,該屬性就是一個User模型的實例。
可使用is_authenticated方法進行判斷,以下:
if request.user.is_authenticated:
# Do something for authenticated users. ... else: # Do something for anonymous users. ...
login(request, user, backend=None)[source]:
在視圖中,使用login()方法登陸用戶。它接收一個HttpRequest參數和一個User對象參數。該方法會把用戶的ID保存在Django的session中。下面是一個認證和登錄的例子:
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: # 返回一個非法登陸的錯誤頁面 ...
logout(request)[source]:
from django.contrib.auth import logout def logout_view(request): logout(request) # Redirect to a success page.
注意,被logout的用戶如何沒登陸,不會拋出錯誤。
一旦logout,當前請求中的session數據都會被清空。
在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('%s?next=%s' % (settings.LOGIN_URL, 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(redirect_field_name='next', login_url=None)[source]
from django.contrib.auth.decorators import login_required @login_required def my_view(request): ...
該裝飾器工做機制:
此時,默認的url中使用的參數是「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變量。
login_required()方法還有一個可選的longin_url參數。例如:
from django.contrib.auth.decorators import login_required @login_required(login_url='/accounts/login/') def my_view(request): ...
注意:若是不指定login_url參數,請確保你的settings.LOGIN_URL和登錄視圖保持正確的關聯。例如:
from django.contrib.auth import views as auth_views url(r'^accounts/login/$', auth_views.login),
經過繼承LoginRequiredMixin類的方式。
在多繼承時,該類必須是最左邊的父類。
class LoginRequiredMixin(New in Django 1.9.)
根據raise_exception參數的不一樣,對於未登錄的用戶請求,響應不一樣的結果。
from django.contrib.auth.mixins import LoginRequiredMixin class MyView(LoginRequiredMixin, View): login_url = '/login/' redirect_field_name = 'redirect_to'
你也能夠直接在視圖中進行過濾:
from django.shortcuts import redirect def my_view(request): if not request.user.email.endswith('@example.com'): return redirect('/login/?next=%s' % request.path) # ...
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): ...
對於上面的例子,email_check接收一個User對象做爲參數,當其返回值是True時,容許執行下面的my_view視圖,不然不容許。
user_passes_test()有兩個可選的參數:login_url和redirect_field_name。前者是跳轉的url後者是url參數字符串。例如:
@user_passes_test(email_check, login_url='/login/') def my_view(request): ...
繼承該類,重寫test_func()方法:
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()方法,指定自定義的名稱用於替代默認的test_func。
permission_required(perm, login_url=None, raise_exception=False)[source]
from django.contrib.auth.decorators import permission_required @permission_required('polls.can_vote') def my_view(request): ...
相似has_perm()方法。權限的格式是<app label>.<permission codename>
。
可選的longin_url參數:
from django.contrib.auth.decorators import permission_required @permission_required('polls.can_vote', login_url='/loginpage/') def my_view(request): ...
raise_exception參數若是給予,裝飾器會拋出PermissionDenied異常,而且用403頁面代替重定向的登錄頁面。例如:
from django.contrib.auth.decorators import login_required, permission_required @login_required @permission_required('polls.can_vote', raise_exception=True) def my_view(request): ...
同上面的loginrequiredmixin相似。
from django.contrib.auth.mixins import PermissionRequiredMixin class MyView(PermissionRequiredMixin, View): permission_required = 'polls.can_vote' # Or multiple of permissions: permission_required = ('polls.can_open', 'polls.can_edit')
能夠自定義重寫get_permission_required()和has_permission()方法
class AccessMixin:
login_url
get_login_url()方法的默認回調函數。
permission_denied_message
拒絕訪問的提示信息。默認是空字符串。
redirect_field_name
get_redirect_field_name()的返回值. 默認是"next".
raise_exception
拋出異常。默認爲False。
get_login_url()
get_permission_denied_message()
get_redirect_field_name()
handle_no_permission()¶
Django沒有爲認證視圖提供默認的模板,你須要本身建立。
有不少種辦法實現這些視圖,最簡單的是使用Django提供的django.contrib.auth.urls,將它添加到URLconf文件中:
urlpatterns = [
url('^', include('django.contrib.auth.urls')), ]
這就至關於添加了下面的URL模式:
^login/$ [name='login'] ^logout/$ [name='logout'] ^password_change/$ [name='password_change'] ^password_change/done/$ [name='password_change_done'] ^password_reset/$ [name='password_reset'] ^password_reset/done/$ [name='password_reset_done'] ^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$ [name='password_reset_confirm'] ^reset/done/$ [name='password_reset_complete']
其中,方括號裏的是url的別名。
固然,也可使用自定義的URL,例如:
from django.contrib.auth import views as auth_views
urlpatterns = [
url('^change-password/$', auth_views.password_change),
]
這些views有一些可選的參數。例如template_name,用於指定視圖須要使用的html模板,看下面的例子:
urlpatterns = [
url(
'^change-password/$', auth_views.password_change, {'template_name': 'change-password.html'} ), ]
全部的這類views都返回一個TemplateResponse實例,對於自定義views能夠將Django提供的view封裝起來使用,例如:
from django.contrib.auth import views def change_password(request): template_response = views.password_change(request) # Do something with `template_response` return template_response
下面是django.contrib.auth模塊包含的全部視圖:
registration/login.html
, redirect_field_name='next', authentication_form=AuthenticationForm, current_app=None, extra_context=None, redirect_authenticated_user=False)登陸視圖
URL name:login (該視圖對應的訪問地址,下同)
可選參數:
template_name: 登陸頁面html文件名。默認爲registration/login.html。
redirect_field_name: 用於登陸URL路徑的參數關鍵字,默認是「next」。
authentication_form:用於認證的調用,默認是AuthenticationForm。
current_app: 2.0版本中將被移除,用request.current_app代替。
extra_context: 額外的數據字典
redirect_authenticated_user:一個布爾值,用於控制已登錄用戶是否能夠訪問登陸頁面。默認是False。
django.contrib.auth.views.login視圖的工做機制是:
使用GET請求時,顯示一個登錄表單,用戶能夠輸入登陸信息。
使用POST請求時,攜帶用戶提供的登錄信息,進行用戶驗證。若是驗證成功,重定向到next參數指定的url地址(若是未指定next參數,則使用settings.LOGIN_REDIRECT_URL中配置的地址,該地址默認爲/accounts/profile/),若是不成功,繼續顯示錶單頁面。
Django不提供registration/login.html模板文件,須要本身編寫。該模板有4個環境變量:
也能夠不使用默認的registration/login.html模板,而是指定別的模板,使用template_name參數,以下:
url(r'^accounts/login/$', auth_views.login, {'template_name': 'myapp/login.html'}),
這裏有一個registration/login.html模板的簡單例子(假定你已經有了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 setup the password_reset view in your URLconf #} <p><a href="{% url 'password_reset' %}">Lost password?</a></p> {% endblock %}
若是使用自定義認證系統,能夠經過authentication_form參數,指定你自定義的認證form顯示在登陸頁面中。這個form必須接受一個request關鍵字參數在它的__init__方法中,而且提供一個get_user()方法用於返回經過認證的user對象。
註銷視圖
URL name: logout
可選參數:
模板變量:
註銷用戶,並返回登陸頁面。
URL name:未設置
可選參數:
用戶修改密碼的頁面
URL name:password_change
可選參數:
模板變量:
用戶修改完密碼後的頁面。
URL name: password_change_done
可選參數:
生成一個一次性的鏈接,並將該鏈接發送到用戶註冊的郵箱地址,用戶經過改地址重置他的密碼。
爲了防止潛在的攻擊,若是提供的郵件地址在系統中不存在,視圖不會發送郵件,用戶也不會受到任何的錯誤信息提示。若是想要提供錯誤信息的話,繼承PasswordResetForm類,並使用password_reset_form參數。
URL name: password_reset
可選參數:
模板變量:
email模板變量:
一個簡單的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 %}
密碼重置後的跳轉頁面
URL name: password_reset_done
可選參數:
顯示一個輸入新密碼的表單
URL name: password_reset_confirm
可選參數:
模板變量:
提示用戶密碼已經成功修改
URL name: password_reset_complete
可選參數:
redirect_to_login(next, login_url=None, redirect_field_name='next')
重定向到登陸頁面,登陸成功後跳轉到指定的url。
必須參數:next,登陸成功後跳轉的url
可選參數:longin_url和redirect_field_name
若是你不想使用內置的視圖,但又不想編寫表單,認證系統提供了內置的表單供你直接使用,它們位於django.contrib.auth.forms。
admin中用於修改用戶密碼的表單。user是它的第一位置參數。
登陸表單,request是它的第一位置參數。
confirm_login_allowed(user):默認狀況下,它拒絕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
或者只容許某些狀態的用戶登陸:
class PickyAuthenticationForm(AuthenticationForm): def confirm_login_allowed(self, user): if not user.is_active: raise forms.ValidationError( _("This account is inactive."), code='inactive', ) if user.username.startswith('b'): raise forms.ValidationError( _("Sorry, accounts starting with 'b' aren't welcome here."), code='no_b_users', )
用戶修改本身密碼的表單
一個表單,用於生成和發送帶有一次性鏈接的郵件,幫助用戶重置密碼。
send_email(subject_template_name, email_template_name, context, from_email, to_email, html_email_template_name=None)
發送郵件的方法。
參數:
設置密碼的表單
admin中修改用戶信息和權限的表單
建立新用戶的ModelForm。它有3個字段,username、password1和password2.
渲染一個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的功能。例如:
{{ perms.foo }},若是登錄用戶有任何foo的權限,該變量就等於True。
雙級屬性查詢至關於User.has_perm。例如:{{ perms.foo.can_vote }}
所以,你能夠在if語句中使用它們,以下面的例子所示:
{% if perms.foo %}
<p>You have permission to do something in the foo app.</p> {% if perms.foo.can_vote %} <p>You can vote!</p> {% endif %} {% if perms.foo.can_drive %} <p>You can drive!</p> {% endif %} {% else %} <p>You don't have permission to do anything in the foo app.</p> {% endif %}
還可使用關鍵字「in」,進行範圍判斷:
{% if 'foo' in perms %}
{% if 'foo.can_vote' in perms %}
<p>In lookup works, too.</p> {% endif %} {% endif %}
當django.contrib.admin與django.contrib.auth都被安裝時,能夠在admin站點中方便的對用戶、組和權限進行管理。
轉載自:http://www.cnblogs.com/feixuelove1009/p/6253553.html