目前已经完成了用户注册,登录验证和商品收藏的功能。但是还不够。还要有用户权限验证
比如 此收藏是否为用户自己的收藏。登录的用户是否有权限更改其他用户的收藏等
涉及到的库:
https://www.django-rest-framework.org/api-guide/permissions/
这两货不一样。 Auth是用于用户登录验证,Perm使用于用户权限验证
Permissions下这些验证库
AllowAny:不管有没有权限都可以访问。
IsAuthenticated: 判断是否已经登录
IsAdminUser:判断用户是否是一个管理员。根据此字段 user.is_staff
判断是否登录:(未登录访问时抛401错误给前端)
from utils.permissions import IsOwnerOrReadOnly
class UserFavViewset(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.DestroyModelMixin, viewsets.GenericViewSet):
"""
用户收藏功能
"""
permission_classes = (IsAuthenticated,)
自定义权限验证Custom permissions
https://www.django-rest-framework.org/api-guide/permissions/#custom-permissions
IP白名单检测:
from rest_framework import permissions
class BlacklistPermission(permissions.BasePermission):
"""
Global permission check for blacklisted IPs.
"""
def has_permission(self, request, view):
ip_addr = request.META['REMOTE_ADDR']
blacklisted = Blacklist.objects.filter(ip_addr=ip_addr).exists()
return not blacklisted
是否是用户本人,否则只读的例子:
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
Object-level permission to only allow owners of an object to edit it.
Assumes the model instance has an `owner` attribute.
"""
def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request,
# so we'll always allow GET, HEAD or OPTIONS requests.
if request.method in permissions.SAFE_METHODS:
return True
# Instance must have an attribute named `owner`.
return obj.owner == request.user
拿到教程项目中使用的例子
# 新建 utils/permissions.py
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
Object-level permission to only allow owners of an object to edit it.
Assumes the model instance has an `owner` attribute.
"""
# 重写BasePermission中的has_object_permission函数
# 用来判定所要操作对象的user字段是否等于request.user字段
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return obj.user == request.user
使用该自定义Permission
# users_operation/views.py
class UserFavViewset(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.DestroyModelMixin, viewsets.GenericViewSet):
"""
用户收藏功能
"""
# ---------------------------------------->这里
permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
这样做完之后 如果要删除或修改的时候 会要求验证权限的。
不过这里也有问题,不能让某一用户获取到所有的收藏信息,其实也没必要全部获取到,获取到自己的不就完事了 。
所以需要重写get_queryset函数
def get_queryset(self):
return UserFav.objects.filter(user=self.request.user)
类中配置queryset变量的参数可以删掉了
然后有一个小bug
要将这里改成self.user.username 否则xadmin获取某一用户收藏时会报错
class UserFav(models.Model):
"""
用户收藏
"""
user = models.ForeignKey(User, verbose_name=u'用户', on_delete=models.CASCADE)
goods = models.ForeignKey(Goods, verbose_name=u'商品', on_delete=models.CASCADE)
add_time = models.DateTimeField(default=datetime.now, verbose_name=u'添加时间')
class Meta:
verbose_name = u'用户收藏'
verbose_name_plural = verbose_name
unique_together = ("user", "goods")
def __str__(self):
# 这里
return self.user.username
之前我们将JWT验证放在了全局的settings.py中。这会有问题
不是每一个页面都需要验证。
所以我们需要将全局的JWT验证放到部分需要用户验证的view中
注释掉
在用户收藏中做示例
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.authentication import SessionAuthentication
class UserFavViewset(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.DestroyModelMixin, viewsets.GenericViewSet):
"""
用户收藏功能
"""
# ------------------------------------------------------> 这个是用于DEF控制台的测试登录用
authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
默认情况下
前端用户是通过表ID来读取相应字段。但是ID字段是数据库自动递增生成的。 但是鬼知道这些ID是对应哪个数据
所以 收藏的话 正常是希望通过商品id就能够访问到
所以需要这么干:
class UserFavViewset(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.DestroyModelMixin, viewsets.GenericViewSet):
"""
用户收藏功能
"""
permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
serializer_class = UserFavSerializer
# 这里
lookup_field = "goods_id"
authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
这节 主要说的是 用户的权限验证,自定义queryset对象,局部JWT验证和generic views字段关联
https://www.django-rest-framework.org/api-guide/generic-views/#genericapiview
完结