一直想写restframework 系列教程 在restframwork中,结合django的原生类,使用django的原生类AbstractUser,我一开始的时候很排斥使用这个类,总想着不继承这个类自己写,但是多次使用自己写的发现问题很多,很多方法都无法使用,例如request.user这个就自己写的类无法继承使用,很烦,最后放弃了使用原生类
使用restframework自带网页展示和postman,可以很直观的让我们了解到restframework权限展示
通过访问http://192.168.56.104:8000/admin/auth/permission/ 这个页面可以看到我们的每一个model在创建之后都默认赋予了can add,can delete,can view,can change四个功能, 在restframework网页中展示就是http://192.168.56.104:8000/goods/ 上面这个图片属于增加can add功能权限 下面为delete,update,select 权限 上述登录用户为超级账号,增删改查权限都有 下面我们限制下 设置一个角色没有修改用户的权限 通过restframework可以看到该用户的确没有修改用户的权限 具体这些权限怎么实现的,其实framework已经给出了答案 在项目的settings.py文件中设置restframework相关参数
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES':(
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'utils.permissions.ModelPermission',
),
'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',),
'PAGE_SIZE': 10
}
我们使用的是’utils.permissions.ModelPermission’自己写的权限认证,只要使用继承使用restframework相关类的都会经过这个脚本文件的过滤,如果不适用restframework类的这个文件不起作用 贴出’utils.permissions.ModelPermission’的关键过滤代码
from .jwt_auth import parse_payload
class ModelPermission(DjangoModelPermissions):
def __init__(self):
self.perms_map['GET'] = ['%(app_label)s.view_%(model_name)s']
def has_permission(self, request, view):
queryset = self._queryset(view)
model_cls = queryset.model
kwargs = {
'app_label': model_cls._meta.app_label,
'model_name': model_cls._meta.model_name
}
list1=[perm % kwargs for perm in self.perms_map['OPTIONS']]
if request.user.is_anonymous:
token = request.META.get('HTTP_AUTHORIZATION', '')
user=parse_payload(token)
request.user=user
res=request.user.roles.values_list('permissions__permission__content_type__app_label','permissions__permission__codename')
perm_list=['.'.join(i) for i in res if i[0]!=None]
queryset = self._queryset(view)
perms = self.get_required_permissions(request.method, queryset.model)
return len([item for item in perms if item not in perm_list])==0
if request.user.is_anonymous: token = request.META.get(‘HTTP_AUTHORIZATION’, ‘’) user=parse_payload(token) request.user=user 这句话的含义是如果使用vue前端过来的用户,对里面的token值进行解析获取到真实的user信息,这一篇暂时不做介绍,后续写vue请求的时候在做处理。这样设置的目的是为了方便vue过来的请求和restframework自带网页过来的请求稍微对get请求做了重写,因为djangomodels的系统权限是can_view权限,所以我们要改写下 return len([item for item in perms if item not in perm_list])==0 这一句表达的含义是如果请求的访问权限不在用户的范围之内,那么就是false,前端无法进行访问也不会展示出来,例如上图的update权限就不能显示 贴出相关的models设计表
from django.db import models
from django.contrib.auth.models import AbstractUser,Permission
class User(AbstractUser):
mobile=models.CharField(max_length=100,verbose_name='手机号码')
address=models.CharField(max_length=200,verbose_name='居住地址')
superior = models.ForeignKey("self", null=True, blank=True, verbose_name="上级主管",on_delete=models.CASCADE)
roles = models.ManyToManyField("role", verbose_name="角色", blank=True)
class Meta:
verbose_name = "用户信息"
verbose_name_plural = verbose_name
ordering = ['id']
def __str__(self):
return self.username
class Menu(models.Model):
"""
菜单
"""
name = models.CharField(max_length=30, unique=True, verbose_name="菜单名")
parent = models.ForeignKey("self", null=True, blank=True, verbose_name="父菜单",on_delete=models.CASCADE)
icon = models.CharField(max_length=50, null=True, blank=True, verbose_name="图标")
oprtype=models.CharField(max_length=100,null=True,blank=True,verbose_name='操作类别')
code = models.CharField(max_length=50, null=True, blank=True, verbose_name="编码")
type=models.IntegerField(null=True,blank=True,choices=((0,'目录'),(1,'菜单'),(2,'按钮'),((3,'API接口'))),verbose_name='菜单类别')
permission=models.ForeignKey(Permission,null=True,blank=True,verbose_name='对应自带权限表对应权限',on_delete=models.CASCADE)
def __str__(self):
return self.name
class Meta:
verbose_name = '菜单'
verbose_name_plural = verbose_name
@classmethod
def get_menu_by_request_url(cls, url):
return dict(menu=Menu.objects.get(url=url))
class Role(models.Model):
"""
角色:用于权限绑定
"""
name = models.CharField(max_length=32, unique=True, verbose_name="角色")
permissions = models.ManyToManyField("menu", blank=True, verbose_name="菜单授权")
desc = models.CharField(max_length=50, blank=True, null=True, verbose_name="描述")
def __str__(self):
return self.name
class Meta:
verbose_name = '角色'
verbose_name_plural = verbose_name
以上为权限管理系统的实现部分代码,主要是继承了DjangoModelPermissions这个类,可以细粒化对orm model的增删改查
|