【Python】django權限管理


參考:http://www.cnblogs.com/esperyong/

參考:https://docs.djangoproject.com/en/1.8/topics/auth/default/#topic-authorization

在Django的世界中,在權限管理中有內置的Authentication系統。用來管理帳戶,組,和許可。還有基於cookie的用戶session。

django中內置的權限控制1-User Model


這篇blog主要用來探討這套內置的Authentication系統。

Django內置的權限系統包括以下三個部分:
用戶(Users)
許可(Permissions):用來定義一個用戶(user)是否能夠做某項任務(task)
組(Groups):一種可以批量分配許可到多個用戶的通用方式

首先需要在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進行學習和使用。

 

>> User對象 <<

首先最重要的開始就是User模型

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):
    ...

1、如果用戶沒登錄, 重定向到/accounts/login/(settings.LOGIN_URL),並且把當前絕對URL作為next參數用get方法傳遞過去

2、如果用戶已登錄, 正常地執行視圖函數

 

>>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)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM