第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

全部開發(fā)者教程

Django 入門教程

Django開發(fā)實戰(zhàn)
35 開發(fā)實戰(zhàn)
首頁 慕課教程 Django 入門教程 Django 入門教程 32 Django 中的權(quán)限管理

Django 中的權(quán)限管理

今天我們會介紹一下 Django 中的自帶的權(quán)限機制,并用一個案例幫助大家理解相關(guān)的權(quán)限用法。

1. Django 中自帶的權(quán)限機制

當 Django 配置文件中的 INSTALL_APPS 包含了 django.contrib.auth 時,就默認啟用了一個簡單的權(quán)限系統(tǒng),提供了為用戶或組分配權(quán)限的方法。這個自帶的權(quán)限系統(tǒng)是基于表的控制,權(quán)限最小粒度是表。也就是說,Django 的權(quán)限系統(tǒng)將控制某個用戶或者用戶組對某個模型表的權(quán)限,一旦賦予某個權(quán)限,將對表中的所有記錄有效。

每個 Model 模型默認只有四個權(quán)限,分別對應著 add、change、delete 和 view。對應的權(quán)限表為 auth_permission,我們可以看看里面的內(nèi)容:

圖片描述

該表只有四個字段,比較簡單:id 為權(quán)限編號、name 為權(quán)限的描述、content_type_id 是關(guān)聯(lián)字段,關(guān)聯(lián)的是模型表、codename 是權(quán)限表示值,在校驗權(quán)限的時候都是使用的這個值。來看看關(guān)聯(lián)表 django_content_type 的內(nèi)容:

圖片描述

可以看到 django_content_type 表中的 id 正是關(guān)聯(lián)前面 auth_permission 表中的 content_type_id 字段,app_lable 表示應用名、model 表示對應應用下的模型表。

為了能演示 Django 的權(quán)限管理功能,我們在應用 hello_app 下新建一個告警消息模型 (alarm_message),并給這個模型顯示定義兩種權(quán)限:查看 (view)、刪除 (delete),這樣對于 alarm_message 會多出兩個權(quán)限 。

class AlarmMessage(models.Model):
    level_choices = (
        (0, '警告'),
        (1, '嚴重'),
        (2, '危險'),
    )
    alarm_title = models.CharField('告警標題', max_length=30)
    alarm_content = models.TextField('告警內(nèi)容', default='暫無內(nèi)容')
    level =  models.SmallIntegerField('高級級別', choices=level_choices, default=0)
    created_at = models.DateTimeField(auto_now_add=True)
    
    def __str__(self):
        return "<%d, %s>" % (self.id, self.title)

    class Meta:
        db_table = 'alarm_message'
        # 通過設置這個會將默認生成的4種權(quán)限情況
        # default_permissions = ()
         permissions = (
            ('view_alarm_message', '查看告警消息'),
            ('delete_alarm_message', '刪除告警消息'),
        )

然后我們使用 makemigrationsmigrate 命令來生成相關(guān)的模型表以及添加對應的權(quán)限信息到權(quán)限表中:

(django-manual) [root@server first_django_app]# python manage.py makemigrations
Migrations for 'hello_app':
  hello_app/migrations/0010_alarmmessage.py
    - Create model AlarmMessage
(django-manual) [root@server first_django_app]# python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, guardian, hello_app, sessions
Running migrations:
  Applying hello_app.0010_alarmmessage... OK

圖片描述

auth_permission表中對應多生成了2個權(quán)限記錄

我們來對應創(chuàng)建用戶以及相應的告警信息,來對應的分配角色:

(django-manual) [root@server first_django_app]# python manage.py shell
Python 3.8.1 (default, Dec 24 2019, 17:04:00) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django.contrib.auth.models import User
>>> s1 = User(username="運維負責人", email="123@163.com")
>>> s1.set_password('master1234')
>>> s1.save()
>>> s2 = User(username="運維部員工", email="227@163.com")
>>> s2.set_password('develop1234')
>>> s2.save()
>>> s3 = User(username="用戶", email="289555@qq.com")
>>> s3.set_password('user1234')
>>> s3.save()

這里我們定義了3個角色:平臺負責人、平臺員工以及普通用戶,他們對告警信息表的權(quán)限分別如下:

  • 平臺負責人:查看 (view) 和 刪除 (delete) 權(quán)限;
  • 平臺普通開發(fā)者:查看 (view) 權(quán)限;
  • 外部用戶:無權(quán)限
>>> User.objects.all().get(username="運維負責人").has_perm('hello_app.view_alarm_message')
False
>>> User.objects.all().get(username="運維負責人").has_perm('hello_app.delete_alarm_message')
False
>>> User.objects.all().get(username='運維負責人').user_permissions.add(126, 127)
>>> User.objects.all().get(username="運維負責人").has_perm('hello_app.view_alarm_message')
True
>>> User.objects.all().get(username="運維負責人").has_perm('hello_app.delete_alarm_message')
True
>>> User.objects.all().get(username="運維負責人").get_all_permissions()
{'hello_app.delete_alarm_message', 'hello_app.view_alarm_message'}

上面添加了運維負責人的查看和刪除告警信息模型的權(quán)限。查看是否具有某個權(quán)限用 has_perm() 方法,參數(shù)是 應用.權(quán)限值;添加權(quán)限用上面的 add() 方法,參數(shù)是權(quán)限表 auth_permission 中對應權(quán)限的 id。此外,對應的刪除權(quán)限用 remove() 方法,設置權(quán)限用 set() 方法;獲取用戶的所有權(quán)限用 get_all_permissions() 方法。以下對應添加平臺開發(fā)員工的權(quán)限:

>>> User.objects.all().get(username="運維部員工").user_permissions.add(126)
>>> User.objects.all().get(username="運維部員工").get_all_permissions()
{'hello_app.view_alarm_message'}

上面這些權(quán)限-用戶信息被記錄到表 auth_user_user_permissions 中,對應生成的結(jié)果如下:

圖片描述

在后端的 View 視圖校驗中,我們可以使用 has_perm()方法來判斷登錄用戶的權(quán)限。

def delete_alarm_message(request):
    if not request.user.has_perm('hello_app.delete_alarm_message')
        return HttpResponse('403 Forbidden')

此外 Django 還提供了一個permission_required() 的裝飾器,可以快速的來校驗用戶是否擁有特定的權(quán)限,用法如下:

@permission_required(perm, login_url=None, raise_exception=False)

perm 參數(shù)為權(quán)限名稱,同樣是 應用.權(quán)限值;login_url 參數(shù)值指的是是當沒有權(quán)限時的跳轉(zhuǎn)地址,沒有設置則不會跳轉(zhuǎn);reise_exception 參數(shù)為 True 是表示當用戶沒有權(quán)限時,不會跳轉(zhuǎn),而是拋出 PermissionDenied 錯誤,返回 403 Forbidden。

2. 案例

有了上面的基礎之后,我們來完成一個簡單的權(quán)限管理案例。首先添加3條告警記錄,用于作為后面測試數(shù)據(jù):

(django-manual) [root@server first_django_app]# python manage.py shell
Python 3.8.1 (default, Dec 24 2019, 17:04:00) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from hello_app.models import AlarmMessage
>>> m1 = AlarmMessage(alarm_title='服務異常告警', alarm_content='后臺認證管理服務不存在,請檢查', level=0)
>>> m1.save()
>>> m2 = AlarmMessage(alarm_title='內(nèi)存告警', alarm_content='主機host-001內(nèi)存使用率100%,請檢查', level=1)
>>> m2.save()
>>> m3 = AlarmMessage(alarm_title='主機掉線', alarm_content='主機host-001已掉線,請檢查', level=2)
>>> m3.save()

我們完成一個登錄頁面,同樣是利用 session 保存登錄狀態(tài)。針對三個不同用戶登錄,我們會顯示不同的結(jié)果:普通用戶直接提示沒有權(quán)限登錄、平臺員工登錄后顯示告警列表、平臺負責人登錄后除了顯示告警列表外,每個記錄對應有個刪除按鈕。

首先來看模板頁面,主要有兩個:登錄頁面 (test_form2.html) 和告警信息 (test_permission.html) 列表頁面。

{# 代碼位置: template/test_form2.html #}
{% load staticfiles %}
<link rel="stylesheet" type="text/css" href="{% static 'css/main.css' %}" />
{% if not success %}
<form action="/hello/test_form_view2/" method="POST">
{% csrf_token %}
<div><span>{{ form.name.label }}</span>{{ form.name }}
<div><span>{{ form.password.label }}</span>{{ form.password }}
<div>
{{ form.save_login }}{{ form.save_login.label }}
</div>
<div><input class="input-text input-red" type="submit" value="登錄" style="width: 214px"/></div>
{% if err_msg %}
<div><label class="color-red">{{ err_msg }}</label</div>
{% endif %}
</form>
{% else %} 
<p>登錄成功</p>
{% endif %}
{# 代碼位置: template/test_permission.html #}
{% load staticfiles %}

<p>登錄用戶:{{ username }}
<a href="/hello/logout/" style="margin-left:30px">登出</a>
</p>
<div>
<table border="1" class="member-table">
  <thead>
  <tr>
    <th></th>
    <th>告警編號</th>
    <th>告警標題</th>
    <th>告警級別</th>
    <th>告警內(nèi)容</th>
    <th>產(chǎn)生時間</th>
    {% if perms.hello_app.delete_alarm_message %}
    <th>操作</th>
    {% endif %}
  </tr>
  </thead>
  <tbody>
  {% for message in messages %}
  <tr>
    <td></td>
    <td>{{ message.id }}</td>
    <td>{{ message.alarm_title }}</td>
    <td>{{ message.level }}</td>
    <td>{{ message.alarm_content }}</td>
    <td>{{ message.created_at|date:"Y-m-d H:m:s" }}</td>
    {% if perms.hello_app.delete_alarm_message %}
    <td><a href="/hello/alarm_delete/{{ message.id }}">刪除</a></td>
    {% endif %}
  </tr>
  {% endfor %}
   </tbody>
</table>
<div >
<div class="page">
</div>
</div>
</div>

我們準備視圖函數(shù),這個視圖函數(shù)是在前面的基礎上進行了改造,代碼如下:

# 代碼位置:hello_app/views.py
# ...

class TestFormView2(TemplateView):
    template_name = 'test_form2.html'

    def get(self, request, *args, **kwargs):
        # print('進入get()請求')
        success = False
        err_msg = ''
        form = LoginForm()
        if request.session.get('has_login', False):
            logined_user = User.objects.all().get(id=int(request.session['user_id']))
            # 判斷登錄的用戶是否有權(quán)查看告警頁面
            if logined_user.has_perm('hello_app.view_alarm_message'):
                # 這一步不能掉,request中添加用戶信息
                request.user = user
                messages = AlarmMessage.objects.all()
                return render(request, "test_permission.html", {"username":logined_user.username, "messages": messages})
            else:
                success = False
                err_msg = "用戶無權(quán)訪問"
        return self.render_to_response(context={'success': success, 'err_msg': err_msg, 'form': form})

    def post(self, request, *args, **kwargs):
        # print('進入post請求')
        form = LoginForm(request.POST)
        success = True
        err_msg = ""
        if form.is_valid():
            login_data = form.clean() 
            name = login_data['name']
            password = login_data['password']
            # 登錄認證
            user = authenticate(username=name, password=password)
            if not user:
                success = False
                err_msg = "用戶名密碼不正確"
            # 判斷登錄用戶是否有權(quán)限
            elif user.has_perm('hello_app.view_alarm_message'):
                request.user = user
                request.session['has_login'] = True
                request.session['user_id'] = user.id
                # 設置100s后過期
                request.session.set_expiry(100)
                messages = AlarmMessage.objects.all()
                return render(request, "test_permission.html", {"username": user.username, "messages": messages})
            else:
                success = False
                err_msg = "用戶無權(quán)訪問"
        else:
            success = False
            err_msg = form.errors['password'][0]
        return self.render_to_response(context={'success': success, 'err_msg': err_msg, 'form': form})

def logout(request, *args, **kwargs):
    if 'has_login' in request.session:
        del request.session["has_login"]
    if 'user_id' in request.session:
        del request.session["user_id"]
    request.session.flush()
    return redirect('/hello/test_form_view2/')

我們這里除了改造原來的登錄請求外,還多加了一個 logout() 方法用于用戶登出操作。接下來準備好 URLConf 配置如下:

# 代碼位置:hello_app/urls.py
# ...

urlpatterns = [
    # ...
    path('test_form_view2/', views.TestFormView2.as_view(), name='test_form_view2'),
    path('logout/', views.logout, name='logout'),
]

最后,我們啟動我們的工程,來看看實際的效果,具體演示演示如下:

3. 小結(jié)

本小節(jié)中,我們學習了 Django 中自帶的權(quán)限管理機制,然后手動完成了一個簡單的權(quán)限管理案例,以加深我們對 Django 內(nèi)部權(quán)限機制的理解。但是這個權(quán)限管理的最小粒度是表,后面我們會使用 django-guardian 框架完成一個更加細粒度的權(quán)限管理案例。