參考:http://www.cnblogs.com/esperyong/html
參考:https://docs.djangoproject.com/en/1.8/topics/auth/default/#topic-authorizationpython
在Django的世界中,在權限管理中有內置的Authentication系統。用來管理賬戶,組,和許可。還有基於cookie的用戶session。web
django中內置的權限控制1-User Modelshell
這篇blog主要用來探討這套內置的Authentication系統。數據庫
Django內置的權限系統包括如下三個部分:
用戶(Users)
許可(Permissions):用來定義一個用戶(user)是否可以作某項任務(task)
組(Groups):一種能夠批量分配許可到多個用戶的通用方式django
首先須要在Django中安裝這個組件:
在settings.py配置好數據庫鏈接,運行python manage.py syncdb 。這一步將生成管理界面使用的數據庫表。
將'django.contrib.auth'和'django.contrib.contenttypes'放到settings.py中的INSTALLED_APPS中。(使用contenttypes的緣由是auth中的Permission模型依賴於contenttypes)編程
咱們能夠執行python manage.py shell來啓動命令行,對其中的一些API進行學習和使用。cookie
>> User對象 <<session
首先最重要的開始就是User模型app
User模型對應於一個用戶,一個賬戶,位於'django.contrib.auth.models'模塊中。
User對象有兩個多對多的屬性分別是:groups和user_permissions
>> 新建User對象 <<
1 from django.contrib.auth.models import User 2 u = User.objects.create_user('test1','test1','aaa')
User對象的Manager,UserManager:
和其餘的模型同樣,User模型類的objects屬性也是一個Manager對象,可是User的Manager對象是自定義的,增長了一些方法:
create_user(username,email=None,password=None)
該方法建立保存一個is_active=True的User對象並返回。username不可以爲空,不然拋出ValueError異常。email和password都是可選的。email的domain部分會被自動轉變爲小寫。password若是沒有提供,則User對象的set_unusable_password()方法將會被調用。
make_random_password(length=10,allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789')
該方法返回一個給定長度和容許字符集的密碼。其中默認的allowed_chars有一些字符沒有,好比i,l等等。
>> User對象的屬性 <<:
username:字符串類型。必填。30個字符之內。
first_name:字符串類型。可選。30個字符之內。
last_name:字符串類型。可選。30個字符之內。
email:可選。
password:明文密碼的hash或者是某種元數據。該屬性不該該直接賦值明文密碼,而應該經過set_password()方法進行賦值,在後面有詳細說明TODO。
is_staff:Boolean類型。用這個來判斷是否用戶能夠登陸進入admin site。
is_active:Boolean類型。用來判斷該用戶是不是可用激活狀態。在刪除一個賬戶的時候,能夠選擇將這個屬性置爲False,而不是真正刪除。這樣若是應用有外鍵引用到這個用戶,外鍵就不會被破壞。
is_superuser:Boolean類型。該屬性用來表示該用戶擁有全部的許可,而無需明確的賦予給他。
last_login:datetime類型。最近一次登錄時間。
date_joined:datetime類型。建立時間。
能夠在新建用戶時直接使用這些屬性:
1 from django.contrib.auth.models import User 2 u = User.objects.create_user('test1','test1','aaa') 3 u.first_name='a' 4 u.first_name='b' 5 u.save()
>> 修改User對象 <<:
1 from django.contrib.auth.models import User 2 u = User.objects.get(username__exact='test1') 3 u.username='test2' 4 u.save()
注意修改完對象屬性須要u.save()。
千萬不要直接給User的password屬性賦值,應該用set_password()方法進行賦值。
Tips:這些用戶屬性就是將數據庫中用戶受權信息的賦值動做。
用python manage.py changepassword *username*來進行修改,須要輸入兩次密碼。
>> User對象方法 <<
像set_password()同樣,除了DjangoModel對象的通用方法以外,User對象有如下特有方法:
is_anonymous():
永遠返回False.用來將User對象和AnonymousUser(未登陸的匿名用戶)對象做區分用的識別方法。一般,最好用is_authenticated()方法。
is_authenticated():
永遠返回True。該方法不表明該用戶有任何的許可,也不表明該用戶是active的,而只是代表該用戶提供了正確的username和password。
get_full_name():
返回一個字符串,是first_name和last_name中間加一個空格組成。
set_password(raw_password):
調用該方法時候傳入一個明文密碼,該方法會進行hash轉換。該方法調用以後並不會保存User對象。
check_password(raw_password):
若是傳入的明文密碼是正確的返回True。該方法和set_password是一對,也會考慮hash轉換。
set_unusable_password():
將用戶設置爲沒有密碼的狀態。調用該方法後,check_password()方法將會永遠返回false。可是若是,調用set_password()方法從新設置密碼後,該方法將會失效,has_usable_password()也會返回True。
has_usable_password():
在調用set_unusable_password()方法以後,該方法返回False,正常狀況下返回True。
get_group_permissions(obj=None):
返回該用戶經過組所擁有的許可(字符串列表每個表明一個許可)。obj若是指定,將會返回關於該對象的許可,而不是模型。
get_all_permissions(obj=None):
返回該用戶所擁有的全部的許可,包括經過組的和經過用戶賦予的許可。
has_perm(perm,obj=None):
若是用戶有傳入的perm,則返回True。perm能夠是一個格式爲:'<app label>.<permission codename>'的字符串。若是User對象爲inactive,該方法永遠返回False。和前面同樣,若是傳入obj,則判斷該用戶對於這個對象是否有這個許可。
has_perms(perm_list,obj=None):
和has_perm同樣,不一樣的地方是第一個參數是一個perm列表,只有用戶擁有傳入的每個perm,返回值纔是True。
has_module_perms(package_name):
傳入的是Django app label,按照'<app label>.<permission codename>'格式。當用戶擁有該app label下面全部的perm時,返回值爲True。若是用戶爲inactive,返回值永遠爲False。
email_user(subject,message,from_email=None):
發送一封郵件給這個用戶,依靠的固然是該用戶的email屬性。若是from_email不提供的話,Django會使用settings中的DEFAULT_FROM_EMAIL發送。
get_profile():
返回一個和Site相關的profile對象,用來存儲額外的用戶信息。這個返回值會在另外一片博文中詳細描述。
django中內置的權限控制2-Login Logout
而在Web應用中,任何的權限系統要作的第一步就是用戶識別,也就是咱們常說的登錄(login)。只有正確的登錄校驗,知道用戶是誰了,纔可以知道用戶能幹什麼,那就是許可(Permission)須要負責解決的事情,而Group則是批量設置許可的時候的一個便利手段。
>> 請求用戶是否登錄的驗證 <<
django有一套方法,能夠在每一個view方法可以接收到的request對象中增長權限驗證相關的方法。要作到這一點,首先須要:
在settings文件中對MIDDLEWARE_CLASSES變量增長上述兩個Middleware類SessionMiddleware和AuthenticationMiddleware。
1 MIDDLEWARE_CLASSES = ( 2 'django.contrib.sessions.middleware.SessionMiddleware', 3 'django.middleware.locale.LocaleMiddleware', 4 'django.middleware.common.CommonMiddleware', 5 'django.middleware.csrf.CsrfViewMiddleware', 6 'django.contrib.auth.middleware.AuthenticationMiddleware', 7 'django.contrib.messages.middleware.MessageMiddleware', 8 'django.middleware.transaction.TransactionMiddleware', 9 )
在view中,咱們就可使用request.user獲取當前的登錄用戶User對象。若是當前用戶沒有登錄,那麼request.user將會是咱們以前所說的AnonymousUser對象。咱們能夠用User對象的is_authenticated()方法將這二者區分開來,咱們可使用django新建一個項目,在view中進行測試:
1 def test(request): 2 if request.user.is_authenticated(): 3 return render_to_response('test.html',{'User_status':'login'}) 4 else: 5 return render_to_response('test.html',{'User_status':'no login'})
在相應的視圖函數前面增長@login_required修飾符能夠實現非登陸用戶禁止訪問:
from django.contrib.auth.decorators import login_required @login_required def test(request): ...
一、若是用戶沒登陸, 重定向到/accounts/login/(settings.LOGIN_URL),而且把當前絕對URL做爲next參數用get方法傳遞過去
二、若是用戶已登陸, 正常地執行視圖函數
>>authenticate驗證<<
使用命令行能夠進行測試,authenticate(username,password)函數須要兩個參數username,password,若是校驗經過則返回User對象,若是校驗不經過返回None,例如:
from django.contrib.auth import authenticate, login def my_view(request): user = authenticate(username='root', password='admin') if user is not None: print "User ok" else: print "password err or no user"
>> login_required <<
定義:django.contrib.auth.decorators.login_required([redirect_field_name=REDIRECT_FIELD_NAME,login_url=None])
login_required方法接受兩個參數:
redirect_field_name:默認值是next。用來定義登錄成功以後的跳回以前訪問界面的url。
login_url:默認值是settings.LOGIN_URL。用來指定登錄界面的url。若是不傳入改參數,就須要確保settings.LOGIN_URL的值是正確設置的。
1 from django.contrib.auth.decorators import login_required 2 3 @login_required(login_url='/admin/') 4 def test(request): 5 ...
示例view:
from django.http import HttpResponse,HttpResponseRedirect from django.shortcuts import render_to_response from django.contrib.auth import authenticate, login, logout from django.contrib.auth.decorators import * def webpage_login(request): """ 頁面 -> 登陸 """ if request.GET.get('next') == None: next_path = '/index/' else: next_path = request.GET.get('next') page = {'next': request.path + '?next=' + next_path} if request.POST.get('user') and request.POST.get('password'): user_str, passwd_str = request.POST.get('user'), request.POST.get('password') if authenticate(username = user_str, password = passwd_str): user_object = authenticate(username = user_str, password = passwd_str) login(request, user_object) return HttpResponseRedirect(request.GET.get('next')) else: return HttpResponse("沒有用戶或密碼錯誤") else: return render_to_response('login.html', page)
示例template:
<body class="login-bg"> <div class="login-body"> <div class="login-heading"> <h1>Login</h1> </div> <div class="login-info"> <form action="{{ next }}" method="post"> <input type="text" class="user" name="user" placeholder="User" required=""> <input type="password" name="password" class="lock" placeholder="Password"> <input type="submit" name="Sign In" value="Login"> </form> </div> </div> </body>
django中內置的權限控制3-許可(Permission) 和 用戶組(Group)
>> 許可(Permissions)<<
當咱們在django中安裝好了auth應用以後,Django就會爲每個你安裝的app中的Model建立三個權限:add/change/delete,執行python manage.py syncdb以後相應的數據會插入到數據庫中的。每一次你執行syncdb,Django都會爲每一個用戶給新出現的Model增長這三個權限。
例如,你建立了一個應用叫作school,裏面有一個模型叫作StudyGroup,那麼你能夠用任何一個user對象執行下面的程序,其結果都返回True:
1 user.hash_perm('school.add_studygroup') 2 user.hash_perm('school.change_studygroup') 3 user.hash_perm('school.delete_studygroup')
咱們也能夠本身定義一些許可,就是在Model類的meta屬性中添加permissions定義。比方說,建立了一個模型類叫作Discussion,咱們能夠建立幾個權限來對這個模型的權限許可進行控制,控制某些人能夠發起討論、發起回覆,關閉討論:
1 class Discussion(models.Model): 2 ... 3 class Meta: 4 permissions = ( 5 ("open_discussion", "Can create a discussion"), 6 ("reply_discussion", "Can reply discussion"), 7 ("close_discussion", "Can remove a discussion by setting its status as closed"), 8 )
執行manage.py syncdb就會把增長的權限信息錄入到後臺數據庫。
經過某一個user的user_permissions屬性,permission_1爲auth_permission表中的id值:
1 user.user_permissions.add(permission_1, permission_2, ...)
刪除權限:
1 user.user_permissions.remove(permission_1, permission_2, ...)
經過user的一個組,而後經過group的permissions屬性:
1 group.permissions.add(permission_1, permission_2, ...)
咱們要判斷一個用戶是否有發討論的權限,咱們能夠用下面的代碼:
1 user.has_perm('school.open_discussion')
Permission類和User類沒什麼特殊的,都是普通的DjangoModel。在第一篇文章中咱們詳細探討了User模型的屬性和方法。在這裏咱們探討一下Permission模型和如何用編程的方式而不是經過預約義而後syncdb的方式建立permission。由於也許在某些時候,須要動態建立並分配權限。
也能夠經過Permission.objects.create()方法添加對應app中models的權限,以下app爲svn中的模型定義Project添加除默認三個權限外的權限:
1 from svn.models import Project 2 from django.contrib.auth.models import Group, Permission 3 from django.contrib.contenttypes.models import ContentType 4 5 content_type = ContentType.objects.get_for_model(Project) 6 permission = Permission.objects.create(codename='project_admin', 7 name='Department administrator', 8 content_type=content_type)