Django - 用戶認證、用戶組、用戶權限

https://www.cnblogs.com/ccorz/p/6358074.htmljavascript

 

auth模塊是Django提供的標準權限管理系統,能夠提供用戶身份認證, 用戶組和權限管理css

auth能夠和admin模塊配合使用, 快速創建網站的管理系統。html

在INSTALLED_APPS中添加'django.contrib.auth'使用該APP, auth模塊默認啓用。java

User

User是auth模塊中維護用戶信息的關係模式(繼承了models.Model), 數據庫中該表被命名爲auth_user.python

User表的SQL描述:程序員

CREATE TABLE "auth_user" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "password" varchar(128) NOT NULL, "last_login" datetime NULL, "is_superuser" bool NOT NULL, "first_name" varchar(30) NOT NULL, "last_name" varchar(30) NOT NULL, "email" varchar(254) NOT NULL, "is_staff" bool NOT NULL, "is_active" bool NOT NULL, "date_joined" datetime NOT NULL, "username" varchar(30) NOT NULL UNIQUE )

auth模塊提供了不少API管理用戶信息, 在必要的時候咱們能夠導入User表進行操做, 好比其它表須要與User創建關聯時:算法

from django.contrib.auth.models import User

建立用戶

user = User.objects.create_user(username, email, password)

創建user對象:sql

user.save()

在此,須要調用save()方法纔可將此新用戶保存到數據庫中。docker

auth模塊不存儲用戶密碼明文而是存儲一個Hash值, 好比迭代使用Md5算法.數據庫

認證用戶

使用authenticate模塊,使用時,先導入模塊:

from django.contrib.auth import authenticate

使用關鍵字參數傳遞帳戶和憑據:

user = authenticate(username=username, password=password)

認證用戶的密碼是否有效, 如有效則返回表明該用戶的user對象, 若無效則返回None。

須要注意的是:該方法不檢查is_active標誌位。

修改用戶密碼

修改密碼是User的實例方法, 該方法不驗證用戶身份:

user.set_password(new_password)

一般該方法須要和authenticate配合使用:

user = auth.authenticate(username=username, password=old_password) if user is not None: user.set_password(new_password) user.save()

登陸

先導入模塊:

from django.contrib.auth import login

login向session中添加SESSION_KEY, 便於對用戶進行跟蹤:

login(request, user)

login不進行認證,也不檢查is_active標誌位, 通常和authenticate配合使用:

user = authenticate(username=username, password=password)
if user is not None: if user.is_active: login(request, user)

auth/__init__.py中能夠看到login的源代碼。

退出登陸

logout會移除request中的user信息, 並刷新session:

from django.contrib.auth import logout def logout_view(request): logout(request)

權限判斷,只容許登陸用戶訪問

@login_required修飾器修飾的view函數會先經過session key檢查是否登陸, 已登陸用戶能夠正常的執行操做, 未登陸用戶將被重定向到login_url指定的位置。若未指定login_url參數, 則重定向到settings.LOGIN_URL

from django.contrib.auth.decorators import login_required @login_required(login_url='/accounts/login/') def my_view(request): ...

Group

django.contrib.auth.models.Group定義了用戶組的模型, 每一個用戶組擁有idname兩個字段, 該模型在數據庫被映射爲auth_group數據表。

User對象中有一個名爲groups的多對多字段, 多對多關係由auth_user_groups數據表維護。Group對象能夠經過user_set反向查詢用戶組中的用戶。

咱們能夠經過建立刪除Group對象來添加或刪除用戶組:

# add group = Group.objects.create(name=group_name) group.save() # del group.delete()

咱們能夠經過標準的多對多字段操做管理用戶與用戶組的關係:

#用戶加入用戶組 user.groups.add(group) #或者 group.user_set.add(user) #用戶退出用戶組 user.groups.remove(group) #或者 group.user_set.remove(user) #用戶退出全部用戶組 user.groups.clear() #用戶組中全部用戶退出組 group.user_set.clear()

Permission

Django的auth系統提供了模型級的權限控制, 便可以檢查用戶是否對某個數據表擁有增(add), 改(change), 刪(delete)權限。

auth系統沒法提供對象級的權限控制, 即檢查用戶是否對數據表中某條記錄擁有增改刪的權限。若是須要對象級權限控制可使用django-guardian

假設在博客系統中有一張article數據表管理博文, auth能夠檢查某個用戶是否擁有對全部博文的管理權限, 但沒法檢查用戶對某一篇博文是否擁有管理權限。

檢查用戶權限

user.has_perm方法用於檢查用戶是否擁有操做某個模型的權限:

user.has_perm('blog.add_article') user.has_perm('blog.change_article') user.has_perm('blog.delete_article')

上述語句檢查用戶是否擁有blog這個app中article模型的添加權限, 若擁有權限則返回True。

has_perm僅是進行權限檢查, 便是用戶沒有權限它也不會阻止程序員執行相關操做。

@permission_required裝飾器能夠代替has_perm並在用戶沒有相應權限時重定向到登陸頁或者拋出異常。

# permission_required(perm[, login_url=None, raise_exception=False]) @permission_required('blog.add_article') def post_article(request): pass

每一個模型默認擁有增(add), 改(change), 刪(delete)權限。在django.contrib.auth.models.Permission模型中保存了項目中全部權限。

該模型在數據庫中被保存爲auth_permission數據表。每條權限擁有id ,name , content_type_idcodename四個字段。

管理用戶權限

User和Permission經過多對多字段user.user_permissions關聯,在數據庫中由auth_user_user_permissions數據表維護。

#添加權限 user.user_permissions.add(permission) #刪除權限: user.user_permissions.delete(permission) #清空權限: user.user_permissions.clear()

用戶擁有他所在用戶組的權限, 使用用戶組管理權限是一個更方便的方法。Group中包含多對多字段permissions, 在數據庫中由auth_group_permissions數據表維護。

#添加權限: group.permissions.add(permission) #刪除權限: group.permissions.delete(permission) #清空權限: group.permissions.clear()

自定義權限

在定義Model時可使用Meta自定義權限:

class Discussion(models.Model): ... class Meta: permissions = ( ("create_discussion", "Can create a discussion"), ("reply_discussion", "Can reply discussion"), )

判斷用戶是否擁有自定義權限:





user.has_perm('blog.create_discussion')


 
 

若需創建py文件進行測試,則在文件開始加入如下代碼便可

複製代碼
#coding:utf-8 

import os 
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "www.settings") 

'''
Django 版本大於等於1.7的時候,須要加上下面兩句
import django
django.setup()
不然會拋出錯誤 django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.
'''
import django

from django.contrib.auth.models import Permission, User #用戶 權限

if django.VERSION >= (1, 7):#自動判斷版本
    django.setup()
複製代碼

查詢一個用戶全部權限,並使其結果轉爲list列表

User.objects.get(username='').user_permissions.values()
#方法一
list(User.objects.get(username='').get_all_permissions())
#方法二

查詢全部權限,並循環輸出

c = Permission.objects.values()
for i in c:
    print i

添加指定權限,此處注意content_type_id是int類型,對應於model的數字

Permission.objects.create(name='add_logentry',content_type_id=1,codename='Can add log entry')
#例:利用查詢權限語句,查看到{u'content_type_id': 1L, 'codename': u'add_logentry', u'id': 1L, 'name': u'Can add log entry'}]相似這樣的列表,

刪除指定權限

Permission.objects.get(codename='Can add log entry').delete()





 

 

 

1. Django權限機制概述

權限機制可以約束用戶行爲,控制頁面的顯示內容,也能使API更加安全和靈活;用好權限機制,能讓系統更增強大和健壯。所以,基於Django的開發,理清Django權限機制是很是必要的。

 

1.1 Django的權限控制

Django用user, group和permission完成了權限機制,這個權限機制是將屬於model的某個permission賦予user或group,能夠理解爲全局的權限,即若是用戶A對數據模型(model)B有可寫權限,那麼A能修改model B的全部實例(objects)。group的權限也是如此,若是爲group C 賦予model B的可寫權限,則隸屬於group C 的全部用戶,均可以修改model B的全部實例。

這種權限機制只能解決一些簡單的應用需求,而大部分應用場景下,須要更細分的權限機制。以博客系統爲例,博客系統的用戶可分爲『管理員』、『編輯』、『做者』和『讀者』四個用戶組;博客系統管理員和編輯具備查看、修改和刪除全部的文章的權限,做者只能修改和刪除本身寫的文章,而讀者則只有閱讀權限。管理員、編輯和讀者的權限,咱們能夠用全局權限作控制,而對於做者,全局權限沒法知足需求,僅經過全局權限,要麼容許做者編輯不屬於本身的文章,要麼讓做者連本身的文章都沒法修改。

上述的應用場景,Django自帶的權限機制沒法知足需求,須要引入另外一種更細的權限機制:對象權限(object permission)。

Object Permission是一種對象顆粒度上的權限機制,它容許爲每一個具體對象受權。仍沿用最開始的例子,若是model B有三個實例 B1,B2 和B3,若是咱們把B1的可寫權限賦予用戶A,則A能夠修改B1對象,而對B2,B3沒法修改。

對group也同樣,若是將B2的可寫權限賦予group C,則隸屬於group C的全部用戶都可以修改B2,但沒法修改B1和B3。結合Django自帶權限機制和object permission,博客系統中做者的權限控制迎刃而解:系統全局上不容許做者編輯文章,而對於屬於做者的具體文章,賦予編輯權限便可。

Django其實包含了object permission的框架,但沒有具體實現,object permission的實現須要藉助第三方app django-guardian,咱們在開發中用調用django guradian封裝好的方法便可。

 

1.2 Django的權限項

Django用permission對象存儲權限項,每一個model默認都有三個permission,即add model, change model和delete model。例如,定義一個名爲『Car』model,定義好Car以後,會自動建立相應的三個permission:add_car, change_car和delete_car。Django還容許自定義permission,例如,咱們能夠爲Car建立新的權限項:drive_car, clean_car, fix_car等等

須要注意的是,permission老是與model對應的,若是一個object不是model的實例,咱們沒法爲它建立/分配權限。

 

2. Django 自帶權限機制的應用

 

2.1 Permission

如上文所述,Django定義每一個model後,默認都會添加該model的add, change和delete三個permission,自定義的permission能夠在咱們定義model時手動添加:

?
1
2
3
4
5
6
7
8
class Task(models.Model):
   ...
   class Meta:
     permissions = (
       ( "view_task" , "Can see available tasks" ),
       ( "change_task_status" , "Can change the status of tasks" ),
       ( "close_task" , "Can remove a task by setting its status as closed" ),
     )

每一個permission都是django.contrib.auth.Permission類型的實例,該類型包含三個字段name, codename 和 content_type,其中 content_type反應了permission屬於哪一個model,codename如上面的view_task,代碼邏輯中檢查權限時要用, name是permission的描述,將permission打印到屏幕或頁面時默認顯示的就是name。

在model中建立自定義權限,從系統開發的角度,可理解爲建立系統的內置權限,若是需求中涉及到用戶使用系統時建立自定義權限,則要經過下面方法:

?
1
2
3
4
5
6
7
8
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)
 

2.2 User Permission管理

User對象的user_permission字段管理用戶的權限:

?
1
2
3
4
5
6
7
8
myuser.user_permissions = [permission_list]
myuser.user_permissions.add(permission, permission, ...) #增長權限
myuser.user_permissions.remove(permission, permission, ...) #刪除權限
myuser.user_permissions.clear() #清空權限
 
##############################################################
# 注:上面的permission爲django.contrib.auth.Permission類型的實例
##############################################################

檢查用戶權限用has_perm()方法:

?
1
myuser.has_perm( 'myapp.fix_car' )

has_perm()方法的參數,即permission的codename,但傳遞參數時須要加上model 所屬app的前綴,格式爲<app label>.<permission codename>

不管permission賦予user仍是group,has_perm()方法均適用

附註:
user.get_all_permissions()方法列出用戶的全部權限,返回值是permission name的list 
user.get_group_permissions()方法列出用戶所屬group的權限,返回值是permission name的list

 

2.3 Group Permission管理

group permission管理邏輯與user permission管理一致,group中使用permissions字段作權限管理:

?
1
2
3
4
group.permissions = [permission_list]
group.permissions.add(permission, permission, ...)
group.permissions.remove(permission, permission, ...)
group.permissions.clear()

權限檢查:

依然使用user.has_perm()方法。

 

2.4 permission_required 裝飾器

權限能約束用戶行爲,當業務邏輯中涉及到權限檢查時,decorator可以分離權限驗證和核心的業務邏輯,使代碼更簡潔,邏輯更清晰。permission的decorator爲permission_required

?
1
2
3
4
from django.contrib.auth.decorators import permission_required
 
@permission_required ( 'car.drive_car' )
def my_view(request):
 

2.5 Template中的權限檢查

Template中使用全局變量perms存儲當前用戶的全部權限,權限檢查能夠參考下面例子:

?
1
2
3
4
5
6
7
8
9
10
{ % if perms.main.add_page % }
       <li class = "dropdown" >
        <a href = "#" rel = "external nofollow" class = "dropdown-toggle" data - toggle = "dropdown" role = "button" aria - expanded = "false" >Pages <span class = "caret" >< / span>< / a>
        <ul class = "dropdown-menu" role = "menu" >
         <li><a href = "{% url 'main:admin_pages' %}" rel = "external nofollow" > All Pages< / a>< / li>
         <li><a href = "{% url 'main:admin_page' %}" rel = "external nofollow" >New Page< / a>< / li>
         <li><a href = "{% url 'main:admin_pages' %}?draft=true" rel = "external nofollow" >Drafts< / a>< / li>
        < / ul>
       < / li>
{ % endif % }
 

3. 基於Django-guardian的object permission的應用

Django-guardian基於django的原生邏輯擴展了django的權限機制,應用django-guardian後,可使用django-guardian提供的方法以及django的原生方法檢查全局權限,django-guardian提供的object permission機制使django的權限機制更加完善。

django-guardian詳細的使用文檔請參考官方文檔,其object permission經常使用方法以下:

?
1
2
3
from guardian.shortcuts import assign_perm, get_perms
from guardian.core import ObjectPermissionChecker
from guardian.decorators import permission_required
 

3.1 添加object permission

添加object permission使用assign_perm()方法,如爲用戶添加對mycar對象的drive_car權限:

?
1
assign_perm( 'myapp.drive_car' , request.user, mycar)

assign_perm()方法也可用於group

?
1
assign_perm( 'myapp.drive_car' , mygroup, mycar)
 

3.2 權限檢查

3.2.1 Global permission

get_perms()方法用於檢查用戶的「全局權限」(global permission),與user.has_perm()殊途同歸,如:

?
1
2
3
4
5
6
7
8
9
10
11
#############################
# It works!
#############################
  if not 'main.change_post' in get_perms(request.user, post):
    raise HttpResponse( 'Forbidden' )
 
#############################
# It works, too!
#############################
if not request.user.has_perm( 'main.change_post' )
   return HttpResponse( 'Forbidden' )

例子中雖然把post object做爲參數傳給get_perms()方法,但它只檢查user的全局權限中是否有main.change_post權限,不少狀況下可用原生的user.has_perm取代,但user和group都可做爲get_perms()的傳入參數,某些狀況下可使代碼更簡潔。

3.2.2 Object permission

Django-guardian中使用ObjectPermissionChecker檢查用戶的object permission,示例以下:

?
1
2
checker = ObjectPermissionChecker(request.user)
print checker.has_perm( 'main.change_post' , post)

3.3 permission_required裝飾器

guardian.decorators.permission_required是django-guardian權限檢查的decorator,既能夠檢查全局權限,又能夠檢查對象權限(object permission),其中,accept_global_perms參數指出是否檢查user的global permission,如:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from guardian.decorators import permission_required
 
class DeletePost(View):
   @method_decorator (permission_required( 'main.delete_post' ,
               (models.Post, 'id' , 'pk' ),
               accept_global_perms = True ))
   def get( self , request, pk):
     try :
       pk = int (pk)
       cur_post = models.Post.objects.get(pk = pk)
       is_draft = cur_post.is_draft
 
       url = reverse( 'main:admin_posts' )
       if is_draft:
         url = '{0}?draft=true' . format (url) 
       cur_post.delete()
     except models.Post.DoesNotExist:
       raise Http404
 
     return redirect(url)

注:
decorator中的(models.Post, ‘id', ‘pk')部分,用於指定object實例,若是忽略這個參數,則不論accept_global_perms值爲True仍是False,均僅僅檢查全局權限。

 

4. 結論

Django原生提供了一種簡單的全局權限(global permission)控制機制,但不少應用場景下,對象權限(object permission)更加有用;django-guardian是目前比較活躍的一個django extension,提供了一種有效的object permission控制機制,與django原生機制一脈相承,推薦使用。

以上就是本文關於Django權限機制實現代碼詳解的所有內容,但願對你們有所幫助。感興趣的朋友能夠繼續參閱本站其餘相關專題,若有不足之處,歡迎留言指出。感謝朋友們對本站的支持!

相關文章
相關標籤/搜索