需求
创建三个页面,每个页面都有对应的访问权限,没有权限的用户是无法访问的。
一、权限
在models中: 创建apage model和b page model
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:
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):
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')
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')
@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:
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:
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:
return redirect(reverse('login'))
if not request.user.has_perm('app.look_a_page'):
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()
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'
@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'
@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里自定义权限;用户添加权限;验证用户是否拥有权限;如何创建组,给组添加权限,用户如何加入组,退出组;以及两个装饰器如何在面向函数和面向对象的方式下使用。
|