需求
创建三个页面,每个页面都有对应的访问权限,没有权限的用户是无法访问的。
一、权限
在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_required和permission_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里自定义权限;用户添加权限;验证用户是否拥有权限;如何创建组,给组添加权限,用户如何加入组,退出组;以及两个装饰器如何在面向函数和面向对象的方式下使用。
本文详细介绍了在Django中实现权限验证的方法,包括通过装饰器进行权限检查,用户组的权限分配,以及如何判断用户是否登录。通过实例展示了如何创建自定义权限,给模型添加权限,以及在视图中验证用户的访问权限。同时,文章还讨论了用户组的创建和管理,以及使用装饰器在函数和面向对象视图中进行权限验证的操作流程。

1666

被折叠的 条评论
为什么被折叠?



