Django——权限验证与cookie&session

本文详细介绍了在Django中实现权限验证的方法,包括通过装饰器进行权限检查,用户组的权限分配,以及如何判断用户是否登录。通过实例展示了如何创建自定义权限,给模型添加权限,以及在视图中验证用户的访问权限。同时,文章还讨论了用户组的创建和管理,以及使用装饰器在函数和面向对象视图中进行权限验证的操作流程。

需求

创建三个页面,每个页面都有对应的访问权限,没有权限的用户是无法访问的。

一、权限

在models中:
创建apage model和b page model

# coding:utf-8
from django.db import models

class Apage(models.Model):
    title = models.CharField(max_length=10)

    def __str__(self):
        return '{}'.format(self.title)

    class Meta:
        permissions = [
            ('look_a_page', 'can get this a page message')
        ]


class Bpage(models.Model):
    title = models.CharField(max_length=10)

    def __str__(self):
        return '{}'.format(self.title)

    class Meta:
        permissions = [
            ('look_b_page', 'can get this b page message')
        ]

在templates中创建a和b两个html,
然后在views中添加这两个page

class A(View):
    TEMPLATE = 'a.html'
    
    def get(self, request):
        return render(request, self.TEMPLATE)


class B(View):
    TEMPLATE = 'b.html'

    def get(self, request):
        return render(request, self.TEMPLATE)

然后把这两个注册到路由中:

from django.urls import path
from .views import Regist, Login, LogoutUser, A, B

urlpatterns = [
    path('regist', Regist.as_view(), name='regist'),
    path('login', Login.as_view(), name='login'),
    path('logout', LogoutUser.as_view(), name='logout'),
    path('a', A.as_view(), name='a_page'),
    path('b', B.as_view(), name='b_page')
]

在这里插入图片描述
可以正常访问

{% if user.has_perm(permission) %}
欢迎访问A page
{% else %}
您无权访问
{% endif %}
class A(View):
    TEMPLATE = 'a.html'

    def get(self, request):

        if not request.user.is_authenticated:  # 如果用户没有登录,就定向到login页面
            return redirect(reverse('login'))

        a_permission = Permission.objects.get(codename='look_a_page')
        print('a')
        print(a_permission)
        print(request.user.has_perm(a_permission))

        if not request.user.has_perm(a_permission):  # 这里验证一下user是否有a权限
            print(a_permission)
            print(request.user.has_perm(a_permission))
            print('test')
            return render(request, self.TEMPLATE, {'error': '您无权访问该页面'})
        else:
            return render(request, self.TEMPLATE, {'info': '欢迎光临'})

在这里插入图片描述
我这里是有权限的。

有两个函数可以通过装饰器额方式验证
# 这两个只能使用在面向函数对象的情况下
from django.contrib.auth.decorators import login_required, permission_required


@login_required(login_url='/login')  # 如果没有登录,会自动跳转到login地址
def a(request):
    return render(request, 'a.html')

如果a没有登录,就会自动跳转到login地址。
在这里插入图片描述
这里的next表示,如果登录完成,接下来就会自动跳转到a地址。

然后对权限进行设置:
permission_required,括号里添加权限app.look_a_page,app是应用名,look_a_page是权限名。
在这里插入图片描述
如果没有权限就直接404了。

@login_required(login_url='/login')  # 如果没有登录,会自动跳转到login地址
@permission_required(perm='a.look_a_page')
def a(request):
    return render(request, 'a.html')

这两个函数login_requiredpermission_required是直接面对函数的,他们会读取request,login_required里面使用了request.user.is_authenticated验证方式,和我们之前写的如下两句话是一样的:

if not request.user.is_authenticated:  # 如果用户没有登录,就定向到login页面
        return redirect(reverse('login'))

permission_required也同样是验证request.user.has_perm(a_permission),如果没找到,就Http404。

然后我们修改一下之前的A,如果没有权限就抛出raise 404

class A(View):
    TEMPLATE = 'a.html'

    def get(self, request):

        if not request.user.is_authenticated:  # 如果用户没有登录,就定向到login页面
            return redirect(reverse('login'))

        a_permission = Permission.objects.get(codename='look_a_page')

        if not request.user.has_perm(a_permission):

            raise Http404
     
        return render(request, self.TEMPLATE)

在这里插入图片描述
就404了。

添加权限

进入shell:

>>> from django.contrib.auth.models import User, Permission
>>> a_permission = Permission.objects.get(codename='look_a_page')
>>> user = User.objects.get(username='cong')
>>> user
<User: cong>
>>> user.user_permissions.add(a_permission)

结果添加上权限后并没有验证成功。

print(request.user.user_permissions.values())

在这里插入图片描述
print一下也能看到权限存在,但是验证没有通过。

原因:user在查询时并不需要把对象传进去,而是直接传app下的权限名。

>>> user.has_perm('app.look_a_page')
True

然后我们修改一下之前的代码。

class A(View):
    TEMPLATE = 'a.html'

    def get(self, request):

        if not request.user.is_authenticated:  # 如果用户没有登录,就定向到login页面
            return redirect(reverse('login'))

        # a_permission = Permission.objects.get(codename='look_a_page')

        if not request.user.has_perm('app.look_a_page'):  # 改了这里,里面不是传a_permission
            raise Http404
        
        return render(request, self.TEMPLATE)

注意下user.has_perm('app.look_a_page')
在这里插入图片描述
现在可以正常访问了。

二、组

创建一个组,给组赋予权限,并把用户添加到组中

在shell中创建一个组。

>>> from django.contrib.auth.models import Group
>>> Group.objects.create(name='b')
<Group: b>
>>> group = Group.objects.get(name='b')
>>> group
<Group: b>

创建了一个组。

然后我们先看一下有哪些权限:

>>> from django.contrib.auth.models import Permission
>>> result = Permission.objects.all()
>>> result
<QuerySet [<Permission: admin | 日志记录 | Can add log entry>, <Permission: admin | 日志记录 | Can change log entry>, <Permission: admin | 日志记录 | Can delete log entry>, <Permission: admin | 日志记录 | Can view log entry>, <Permission: app | apage | Can add apage>, <Permission: app | apage | Can change apage>, <Permission: app | apage | Can delete apage>, <Permission: app | apage | can get this a page message>, <Permission: app | apage | Can view apage>, <Permission: app | bpage | Can add bpage>, <Permission: app | bpage | Can change bpage>, <Permission: app | bpage | Can delete bpage>, <Permission: app | bpage | can get this b page message>, <Permission: app | bpage | Can view bpage>, <Permission: auth || Can add group>, <Permission: auth || Can change group>, <Permission: auth || Can delete group>, <Permission: auth || Can view group>, <Permission: auth | 权限 | Can add permission>, <Permission: auth | 权限 | Can change permission>, '...(remaining elements truncated)...']>

很多很多。。
然后我们再去数据库中看一下
在这里插入图片描述
可以看到我们即使不添加look_a_page权限,我们在创建数据库的时候也拥有了add,change,delete,view这四个权限。
在这里插入图片描述
这个content_type_id就是因为在django_content_type表中,apage和bpage的id是7和8.

组添加权限

>>> permissions = Permission.objects.filter(content_type_id=8)
>>> permissions
<QuerySet [<Permission: app | bpage | Can add bpage>, <Permission: app | bpage | Can change bpage>, <Permission: app | bpage | Can delete bpage>, <Permission: app | bpage | can get this b page message>, <Permission: app | bpage | Can view bpage>]>
>>> for i in permissions:
...     group.permissions.add(i)
...
>>> group.permissions.values()
<QuerySet [{'id': 30, 'name': 'Can add bpage', 'content_type_id': 8, 'codename': 'add_bpage'}, {'id': 31, 'name': 'Can change bpage', 'content_type_id': 8, 'codename': 'change_bpage'}, {'id': 32, 'name': 'Can delete bpage', 'content_type_id': 8, 'codename': 'delete_bpage'}, {'id': 34, 'name': 'can get this b page message', 'content_type_id': 8, 'codename': 'look_b_page'}, {'id': 33, 'name': 'Can view bpage', 'content_type_id': 8, 'codename': 'view_bpage'}]>

可以看到组里有的这些权限。

用户添加的组里

现在我们要把用户添加到组里

>>> user.groups.add(group)
>>> user
<User: cong>
>>> user.groups.all()
<QuerySet [<Group: b>]>
>>> user.user_permissions.values()
<QuerySet [{'id': 29, 'name': 'can get this a page message', 'content_type_id': 7, 'codename': 'look_a_page'}]>

但是看一下user的权限,依旧是之前的那些权限。

现在我们先去views里给B添加一些权限

class B(View):
    TEMPLATE = 'b.html'

    def get(self, request):

        b_permission = Permission.objects.filter('look_b_page').first()

        # 用Q查询,查询组里有没有对应权限
        # 去用户的groups里面看一下,有没有b_permission,或者是user里有没有b_permission,为了防止重复,去重
        users = User.objects.filter(Q(groups_permissions=b_permission) |
                                    Q(user_permission=b_permission)).distinct()
        print(users)

        return render(request, self.TEMPLATE)

结果。。
在这里插入图片描述
原来是filter没有写codename参数b_permission = Permission.objects.filter(codename='look_b_page').first()
然后又发现一个bug,这里写的不对,要写成下面这样

users = User.objects.filter(Q(groups__permissions=b_permission) |
                                    Q(user_permissions=b_permission)).distinct()

在这里插入图片描述
然后再加一个判断:如果请求页面的用户不在users中,就404

        if request.user not in users:
            raise Http404()

在这里插入图片描述
可以进来,说明有权限。

判断用户是否登录新方法

from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required


class B(View):
    TEMPLATE = 'b.html'

    # 在第一层装饰器中把 login_required放进去,如果没有登录,就跳转到login
    # 这样login_required就可以面向对象使用了
    @method_decorator(login_required, name='login')
    def get(self, request):

然后再看如何用装饰器添加权限。

from django.contrib.auth.decorators import login_required, permission_required


class B(View):
    TEMPLATE = 'b.html'

    # 在第一层装饰器中把 login_required放进去,如果没有登录,就跳转到login
    # 这样login_required就可以面向对象使用了
    @method_decorator(login_required)
    @method_decorator(permission_required('app.look_b_page'))
    def get(self, request):

        b_permission = Permission.objects.filter(codename='look_b_page').first()

导入permission_required,然后再加上我们需要验证的权限permission_required('app.look_b_page')

总结

自定义权限:创建一个model,在model的meta里自定义权限;用户添加权限;验证用户是否拥有权限;如何创建组,给组添加权限,用户如何加入组,退出组;以及两个装饰器如何在面向函数和面向对象的方式下使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值