1. 程式人生 > >Django中Admin管理與許可權管理(三)————模組的鑑權操作

Django中Admin管理與許可權管理(三)————模組的鑑權操作

通知模組的鑑權操作
1.定義許可權
這裡需要給大家提的是,在我們新建模型完成之後,系統會自動的給這個模型定義三個許可權。我們可以通過認證和授權中的組來進行檢視。
如下圖所示,我們可以看到預設新增的三個許可權資訊。


當然啦,在實際執行環境中,我們難免要對許可權進行擴充套件。所以我們就需要自定義自己需要的許可權了。
下面就來介紹自定義許可權的過程。方法很簡單,在我們自定義的GfzNotice中新增permissions。我們這裡只新增了一個屬性,當然了,你可以新增多個屬性,屬性之間以英文符號逗號分割。
# 定義Notice模型
class GfzNotice(models.Model):
    ...
    class Meta:

        ...
        permissions = (
            ("scan_noticee", u"檢視通知"),
        )
修改完成後儲存,然後按照附錄1的3中所示內容完成資料庫的同步。再次檢視許可權列表時,我們就可以看到notice/通知下面多了一個可以選擇的許可權,叫做檢視通知了。


2.許可權的配置
1.分配到組(Group)
這裡需要給大家說的是,將許可權分配到組的話,就是這個組擁有哪些許可權,這個人就擁有哪些許可權。具體組的許可權配置如下:


將要分配的許可權放在右邊,然後上面可以自定義一個方便管理的名稱,我們這裡就定義了一個通知管理組。接下來就是給將組的許可權分配給個人。

按照下圖所示,將要分配的組移動到右邊選中的組中,之後點選儲存即可完成相關許可權配置過程。


2.分配到個人
有了前面將許可權分配到組的過程後,接下來將許可權分配給個人就顯得十分簡單了。如下圖所示,我們只把檢視通知的許可權分配給個人的話,只需要選中,點選右下角的儲存按鈕即可。


3.許可權的使用
前面我們已經瞭解了許可權的定義和配置的相關過程,接下來需要我們完成的就是許可權怎麼使用了。我們主要會圍繞下面幾個步驟帶大家一起來完成許可權的配置和使用過程。
1.設定路由
首先我們在主的路由(fz應用下的urls.py檔案)新增如下配置:
urlpatterns = [
    ...
    # 通知入口
    url(r'^notice/', include('notice.urls')),

]
這樣所有對notice的請求都會交給notice應用下的urls來處理了。
這時我們再來配置notice下的urls.py檔案:
# -*- coding:utf-8 -*-
from django.conf.urls import url
from . import views
urlpatterns = [
    # add by chr 20160719
    # 針對於什麼值都不傳遞過來的情況
    url(r'^$', views.home, name='home'),
    # 傳遞不帶/的值 進行處理
    url(r'^(?P<slug>\w+)$', views.URLControl.as_view(), name='urlControl'),
    # 傳遞帶/的值 進行處理
    url(r'^(?P<slug>\w+)/$', views.URLControl.as_view(), name='urlControl'),
]
這裡我們主要對三種情況進行鑑權,一種是什麼值都沒傳過來,一種是傳了引數但沒有帶/,還有一種就是穿了引數且帶了/。
2.編寫View.py(介面鑑權)
對於View.py中鑑權的方式大體上分為3中,第一種是在函式前新增修飾符@login_required,第二種方式是在函式的具體實現過程中利用是否驗證的屬性判斷,即request.user.is_authenticated()是否為true,這兩種方式都是限定了沒有登入的使用者是返回不了值的。第三種方式也是加修飾符,但這個是對已經登入的使用者做的限制,修飾符的內容是permission_required+具體要判斷的許可權的值。
# -*- coding:utf-8 -*-
from django.shortcuts import render, get_object_or_404
from django.http import Http404, HttpResponseRedirect
from django.views.generic import View
from django.core.exceptions import PermissionDenied
from django.contrib.auth.decorators import login_required
from notice.models import GfzNotice
from django.contrib.auth.decorators import permission_required
# Create your views here.
# add by chr 20160719
# 返回主頁面
@login_required
def home(request):
    noticelist = GfzNotice.objects.order_by('list_order')
    return render(request, 'notice/home.html', {'noticelist': noticelist})
# 路由控制
class URLControl(View):
    # API處理
    def post(self, request, *args, **kwargs):
        # 獲取要對使用者進行什麼操作
        raise PermissionDenied
    # 頁面處理
    def get(self, request, *args, **kwargs):
        if not request.user.is_authenticated():
            return HttpResponseRedirect('/login')
        slug = self.kwargs.get('slug')
        if slug[0:4] == 'view':
            return getNotice(request, slug[4:])
        # 如果是get請求直接返回404頁面
        raise Http404
@permission_required('notice.scan_noticee')
def getNotice(request, iobj):
    detailnotice = get_object_or_404(GfzNotice, pk = iobj)
    return render(request, 'notice/detail.html', {'detailnotice': detailnotice})
3.頁面鑑權
頁面中進行授權的方式也很簡單,新增{% if perms.notice.scan_noticee %}這句話的意思就是判斷當前使用者是否有notice下的scan_noticee許可權。
{% extends "./accounts/base.html"%}
{% block title %}
    <title>通知列表</title>
{% endblock %}
{% block main %}
<div class="wrapper">
    <div class="content-wrapper" style="min-height: 1036px;">
    <!-- Content Header (Page header) -->
    <section class="content-header">
      <h1>
        通知管理
        <small>系統最新的通知</small>
      </h1>
    </section>
    <!-- Main content -->
    <section class="content">
      <!-- COLOR PALETTE -->
      <div class="box box-default color-palette-box">
        <div class="box-header with-border">
          <h3 class="box-title"><i class="fa fa-tag"></i> 最新的通知 </h3>
        </div>
          <div class="box-body">
              {% if perms.notice.scan_noticee %}
              <table class="table table-bordered">
                <tbody><tr>
                  <th style="width: 10px">#</th>
                  <th>通知</th>
                  <th>釋出時間</th>
                  <th>釋出人</th>
                  <th>修改時間</th>
                </tr>
                 {% for notice in noticelist %}
                <tr>
                  <td>1.</td>
                  <td><a class="txtlink" href="/notice/view{{notice.id}}">{{notice.title}}</a></td>
                  <td>{{notice.date_create}}</td>
                  <td>{{notice.crate_man}}</td>
                  <td>{{notice.date_mod}}</td>
                </tr>
                {% endfor %}
              </tbody></table>
               {% else %}
                    你沒有訪問該模組的許可權哦
               {% endif %}
          </div>
      </div> 
 <div>
</div>
    </section>
    <!-- /.content -->
  </div>
</div>
{% endblock %}
4.單元測試
具體單元測試的內容,請參考程式碼中的註釋,這裡不做細講。測試的內容還是分成了三步 第一測試沒有登入的使用者;第二測試已經登入的使用者,因為在第二步中需要測試通知的詳細頁,所以要往通知表中插入一條記錄,同時這一步中需要建立兩個使用者,一個有許可權,一個沒有許可權分別進行測試;最後一個就是登出之後再進行相關測試了。
# -*- coding:utf-8 -*-
from django.shortcuts import get_object_or_404
from django.test import TestCase
from django.test.utils import setup_test_environment
from django.test import Client
from accounts.models import FzjUser
from notice.models import GfzNotice
# Create your tests here.
# add by chr 20160719
class HomeTest(TestCase):
    def testApis(self):
        setup_test_environment()
        client = Client()
        # 對於沒有登入的使用者進行單元測試
        response = client.get('/notice')
        self.assertEqual(response.status_code, 301)
        response = client.get('/notice/')
        self.assertEqual(response.status_code, 302)
        response = client.get('/notice/view1')
        self.assertEqual(response.status_code, 302)
        response = client.get('/notice/view1/')
        self.assertEqual(response.status_code, 302)
        # 給臨時資料庫建立一個登入賬號 使用者名稱為chr 密碼為123 --- 該使用者為超級管理員
        FzjUser.objects.create_superuser(username='chr', password='123', email='')
        # 新增一條通知記錄 方便下面進行介面的測試
        gfzNotice = GfzNotice()
        gfzNotice.title = 'test'
        gfzNotice.content = 'test'
        gfzNotice.crate_man = get_object_or_404(FzjUser, pk = 1)
        gfzNotice.date_mod = '2016/7/19'
        GfzNotice.save(gfzNotice)
        # 使用剛建立的使用者資訊登入系統平臺 如果登入出錯 測試會報錯
        self.assertEqual(client.login(username='chr', password='123'), True)
        # 下面就以登入成功的使用者來完成相關的操作 對於存在的介面返回200
        response = client.get('/notice')
        # 重轉向到/notice/
        self.assertEqual(response.status_code, 301)
        response = client.get('/notice/')
        self.assertEqual(response.status_code, 200)
        response = client.get('/notice/view1')
        self.assertEqual(response.status_code, 200)
        response = client.get('/notice/view1/')
        self.assertEqual(response.status_code, 200)
        # 對於不存在的介面返回404 沒有找到
        response = client.get('/notice/getOther')
        self.assertEqual(response.status_code, 404)
        response = client.get('/notice/getOther/')
        self.assertEqual(response.status_code, 404)
        # 將登入的賬號登出 然後重新測試相關介面
        client.logout()
        # 給臨時資料庫建立一個登入賬號 使用者名稱為chr 密碼為123 --- 該使用者為普通使用者
        FzjUser.objects.create_user(username='chr23899', password='123', email='')
        # 使用剛建立的使用者資訊登入系統平臺 如果登入出錯 測試會報錯
        self.assertEqual(client.login(username='chr23899', password='123'), True)
        # 下面就以登入成功的使用者來完成相關的操作 對於存在的介面返回200
        # 跳轉到 /notice/ 目錄下
        response = client.get('/notice')
        self.assertEqual(response.status_code, 301)
        response = client.get('/notice/')
        self.assertEqual(response.status_code, 200)
        # 沒有許可權訪問 導致跳轉
        response = client.get('/notice/view1')
        self.assertEqual(response.status_code, 302)
        response = client.get('/notice/view1/')
        self.assertEqual(response.status_code, 302)
        # 對於不存在的介面返回404 沒有找到
        response = client.get('/notice/getOther')
        self.assertEqual(response.status_code, 404)
        response = client.get('/notice/getOther/')
        self.assertEqual(response.status_code, 404)
        # 將登入的賬號登出 然後重新測試相關介面
        client.logout()
        response = client.get('/notice/view1')
        self.assertEqual(response.status_code, 302)
        response = client.get('/notice/view1/')
        self.assertEqual(response.status_code, 302)
到這單元測試的部分就算完成了,接下來我們執行以下單元測試:出現了下面的結果。恭喜你,單元測試的結果是成功的了。


5.實現效果
1.對於有許可權的使用者:
訪問通知列表的時候可以看到如下圖所示的內容。


對於通知詳情的話,就可以看到下面的效果


2.對於沒有許可權的使用者:
這是訪問通知列表的時候,就出現了“你沒有訪問該模組的許可權哦”,這就是在頁面中設定的相關鑑權。


如果這是通過地址http://127.0.0.1:8000/notice/view1去獲取通知的詳情頁面的話,這個使用者是獲取不到的,因為我們在View.py中對詳細的函式進行了許可權的控制。
4.小結
通過學習,我們已經對django自帶的鑑權有了很好的瞭解和掌握了。