【Python】django權限管理

參考: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)
相關文章
相關標籤/搜索