Django默認許可權機制介紹及實踐
- 2019 年 10 月 12 日
- 筆記
演示Django版本為當前最新版本v2.2
當Django配置文件中的INSTALL_APPS
包含了django.contrib.auth
時,就默認啟用了一個簡單的許可權系統,提供了為用戶或組分配許可權的方法
之所以說簡單呢?主要是因為:
- 默認的許可權系統是基於表的控制,許可權最小粒度是表
也就是說,假如有一個Blog表,我們可以賦予用戶或組對Blog表有delete的許可權,那麼用戶或組成員就可以刪除全部Blog,是不能控制用戶只能刪除自己創建的blog的
如果希望用戶只能刪除自己創建的Blog,不能刪除別人創建的Blog,這種需求Django默認的許可權管理就無法實現了,需要用到object permission
對象許可權,有第三方模組實現了對象許可權,如django-guardian,你可以直接使用,或者也可以自己實現對象許可權,具體思路可參考這篇文章:Django內置許可權擴展案例
- 每個Model模型默認只有四個許可權,分別是添加
add_
、修改change_
、刪除delete_
、查看view_
,這些許可權記錄在Permission表中,表數據如下:
默認許可權的創建是通過Django的訊號signals實現的,使用了post_migrate
訊號,在每次執行migrate操作時都會為新的Model模型創建默認許可權,關於Django的訊號Signals介紹和使用可以查看這篇文章:Django使用Signals監測model欄位變化發送通知,
自定義許可權
默認的許可權名字和描述都是英文的,且只有四個,如果你不想用默認的幾個許可權,想要自定義的話,可以這樣做:
class Blog(models.Model): title = models.CharField(max_length=256, verbose_name='標題') content = models.TextField(blank=True, null=True, verbose_name='內容') class Meta: default_permissions = () permissions = ( ("change_blog", "修改部落格"), ("delete_blog", "查看部落格"), ("publish_blog", "發布部落格"), )
default_permissions: 清空默認的許可權
permissions: 設置許可權,內容是一個嵌套的列表,列表第一個欄位是codename
,第二個欄位為name
注意:如果你使用了django默認的admin的話,建議保留4個默認許可權,可以添加新許可權
許可權修改
如果你用了Django自帶的admin,在migrate之後就能在admin的user和group兩個表中看到新添加的許可權了
當然你也可以在程式中來添加或修改許可權
用戶許可權修改方法:
ops = User.objects.get(id=2) ops.user_permissions.add(25, 26) ops.user_permissions.set([26, 27]) ops.user_permissions.remove(26, 27) ops.user_permissions.clear()
組許可權修改方法:
coffee = Group.objects.get(id=1) coffee.permissions.add(25) coffee.permissions.set([26,27]) coffee.permissions.remove(25) coffee.permissions.clear()
其中add
為添加,set
為設置,remove
為移除,clear
為清空,add
跟set
的區別是add
會在原有許可權的基礎上加新許可權,而set
會清空原有許可權設置成新的許可權,後邊的參數25,26,27可以為Permission的ID或者是Permission對象,例如這樣也是可以的:
p = Permission.objects.get(id=25) coffee.permissions.add(p)
給組賦予許可權,組內的所有用戶會自動的擁有該組的許可權,例如用戶ops-coffee
隸屬於組SRE
,SRE
組對Blog表有修改許可權,那麼即便是沒有單獨給Y37
用戶分配任何許可權,他也會有對Blog表的修改許可權
許可權查看
get_all_permissions()
列出用戶的所有許可權:
>>> User.objects.get(username='ops-coffee').get_all_permissions() {'blog.publish_blog', 'blog.delete_blog', 'auth.add_group', 'blog.change_blog'}
get_group_permissions()
列出用戶所屬組的許可權:
>>> User.objects.get(username='ops-coffee').get_group_permissions() {'blog.publish_blog', 'blog.change_blog', 'blog.delete_blog'}
許可權校驗
用戶對象可以通過has_perm
方法來判斷用戶是否擁有某個許可權:
>>> User.objects.get(username='ops-coffee').has_perm('blog.change_blog') True >>> User.objects.get(username='ops-coffee').has_perm('blog.delete_blog') True
has_perm 的參數由<app label>.<permission codename>
兩部分組成,例如blog.delete_blog
表示的就是名字為blog
的APP下的delete_blog
許可權
後端View校驗許可權
可以直接在view中通過if判斷用戶許可權,例如:
def ops_coffee_view(request): if not request.user.has_perm('blog.change_blog') return HttpResponse('403 Forbidden')
為了方便,Django還提供了一個permission_required()
的裝飾器,可以快速的來校驗用戶是否擁有特定的許可權,用法如下:
@permission_required(perm, login_url=None, raise_exception=False)
三個參數的意思分別是:
perm: 必須有,許可權名稱,同has_perm
一樣
login_url: 非必須,登陸的url地址,當你沒有許可權時自動跳轉到登陸頁,這裡可以設置登陸地址的url
reise_exception: 非必須,當為True時,如果用戶沒有許可權,則不會跳轉到登陸頁,而是引發PermissionDenied
錯誤,返回403 Forbidden
如下例子,判斷用戶是否有blog
的APP的change_blog
許可權,如果沒有則返回403錯誤
@permission_required('blog.change_blog', raise_exception=True) def ops_coffee_view(request): ...
前端Template中校驗許可權
當前登陸用戶的許可權保存在模版變數{{ perms }}
中,可以在模版中通過if判斷用戶是否擁有相應的許可權而開放對應的內容,例如對於側邊欄菜單只顯示用戶有許可權訪問的,就可以這麼寫:
{% if perms.cmdb.view_project %} <li><a href="{% url 'project-list-url' %}"></i> 項目列表</a></li> {% endif %} {% if perms.cmdb.view_service %} <li><a href="{% url 'service-list-url' %}"></i> 服務列表</a></li> {% endif %} {% if perms.cmdb.view_environment %} <li><a href="{% url 'environment-list-url' %}"></i> 環境列表</a></li> {% endif %}
至此,Django的默認許可權系統介紹完成,默認許可權在小型項目中能滿足大部分的需求,如果對許可權控制有更高的要求可以關注前文中介紹的django-guardian
項目或自己實現
相關文章推薦閱讀: