DjangoRESTframework-用户状态校验

文章介绍了在DjangoRESTframework中如何进行用户状态校验,包括利用djangosession机制验证用户登录状态,设置全局认证方案,以及在基于函数的视图、APIView类视图和视图集上应用认证。同时,文章展示了如何禁用特定接口的全局认证以及自定义权限类来限制只有项目管理员才能进行操作。
摘要由CSDN通过智能技术生成

DjangoRESTframework-用户状态校验

django session机制

django默认的用户信息存储方案为session机制,有内置的装饰器可以验证当前请求是否携带用户认证信息

修改sqtp应用目录下的views.py文件中的user_list视图,加上@login_required装饰器

from django.contrib.auth.decorators import login_required

@api_view(['GET'])
def current_user(request):
    # 如果当前用户处于登录状态
    if request.user.is_authenticated:
        serializer = UserSerializer(request.user)
        # 返回当前用户信息
        return Response(data=serializer.data)
    else:
        return Response(data={'msg': '用户未登录', 'retcode': status.HTTP_403_FORBIDDEN, 'to': 'login.html'},status=status.HTTP_403_FORBIDDEN)   # 重定向到登录页面

此时,如果访问http://127.0.0.1:8888/api/users/接口没有带上session信息,就会返回404

DRF全局认证方案

采用 Django REST framework 框架的 DEFAULT_AUTHENTICATION_CLASSES 设置全局的默认身份验证方案

settings.py文件下添加DRF全局认证方案

# rest框架配置
REST_FRAMEWORK = {
    # 默认的渲染器
    'DEFAULT_RENDERER_CLASSES': (
        'utils.renderers.MyRenderer',
    ),
    # 全局配置异常处理模块
    'EXCEPTION_HANDLER': 'utils.exception.my_exception_handler',
    # 全局认证模块
    'DEFAULT_AUTHENTICATION_CLASSES':('rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication'),
    # 全局权限模块
    'DEFAULT_PERMISSION_CLASSES':('rest_framework.permissions.IsAuthenticated',),
}
基于函数的视图

使用 @api_view 装饰器基于函数的视图,通过添加装饰器设置身份验证方案

示例:

from rest_framework.decorators import api_view, authentication_classes, permission_classes


@api_view(['GET'])
@authentication_classes((SessionAuthentication, BasicAuthentication))
@permission_classes((IsAuthenticated,))
def example_view(request, format=None):
   content = {
       'user': unicode(request.user), # `django.contrib.auth.User` 实例。
       'auth': unicode(request.auth), # None
   }
   return Response(content)

修改sqtp应用目录下的views.py文件中的user_list视图

from rest_framework.decorators import api_view, authentication_classes, permission_classes

# 用户
@api_view(['GET'])
@authentication_classes((SessionAuthentication, BasicAuthentication))
@permission_classes((IsAuthenticated,))
def user_list(request):
    query_set = User.objects.all()
    serializer = UserSerializer(query_set,many=True)
    return Response(serializer.data)

使用swagger访问访问http://127.0.0.1:8888/api/users/接口,会返回error信息:身份认证信息未提供。进行登录后,再次访问,即可获取接口信息

基于 APIView 类视图

使用基于 APIView 类视图的方式,在每个view或每个viewset基础上设置身份验证方案

示例:

from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

class ExampleView(APIView):
   authentication_classes = (SessionAuthentication, BasicAuthentication)
   permission_classes = (IsAuthenticated,)
   def get(self, request, format=None):
       content = {
           'user': unicode(request.user), # `django.contrib.auth.User` 实例。
           'auth': unicode(request.auth), # None
       }
       return Response(content)
基于视图集

示例:

from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

class ExampleView(viewsets.ModelViewSet):
    queryset = Example.objects.all()
    serializer_class = ExampleSerializer
    # 权限--使用全局认证
    authentication_classes = ((SessionAuthentication, BasicAuthentication))
    permission_classes = ((IsAuthenticated,))

修改sqtp应用目录下的views.py文件中的ProjectViewSet视图集

from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.permissions import IsAuthenticated

class ProjectViewSet(viewsets.ModelViewSet):
    queryset = Project.objects.all()
    serializer_class = ProjectSerializer
    # 权限--使用全局认证
    authentication_classes = ((SessionAuthentication, BasicAuthentication))
    permission_classes = ((IsAuthenticated,))

修改sqtp应用目录下的serializers.py文件,对序列化器展示的内容进行修改,前端提交的接口信息、返回给前端的接口内容需要用到这些字段

# 项目部分序列化器
class ProjectSerializer(serializers.ModelSerializer):
    class Meta:
        model = Project
        fields = ['id','admin','name','status','version','desc','create_time','update_time']

浏览器中输入http://127.0.0.1:8888/projects.html,进入项目管理页面,会弹出提示登录弹框

在这里插入图片描述

不进行登录,新增项目,接口会报错,返回身份认证信息未提供错误信息

在这里插入图片描述

而进行登录后,新增项目则可以成功

局部接口禁用全局认证

对于注册、登录、登出和获取当前用户信息视图这四个接口,是不需要设置全局认证的,像现在这样,就会出现进入注册页面,就会弹出一个弹框要求登录,这显然是不合理的

修改sqtp应用目录下的views.py文件中的注册、登录、登出和获取当前用户信息视图这四个视图函数,添加装饰器@permission_classes(()),装饰器中为空元组

@api_view(['POST'])
@permission_classes(())
def register(request):
    # 获取注册信息--序列化器
    serializer = RegisrerSerializer(data=request.data)
    if serializer.is_valid():    #自动根据模型定义来判断数据入参是否合法
        user = serializer.register()    # 创建用户数据
        auth.login(request,user)    # 完成用户登录状态的设置
        return Response(data={'msg':'register success','is_admin':user.is_superuser,'retcode':status.HTTP_201_CREATED},status=status.HTTP_201_CREATED)
    return Response(data={'msg':'error','retcode':status.HTTP_400_BAD_REQUEST,'error':serializer.errors},status=status.HTTP_400_BAD_REQUEST)


@api_view(['POST'])
@permission_classes(())
def login(request):
    # 获取登录信息--序列化器
    serializer = LoginSerializer(data=request.data)
    user = serializer.validate(request.data)
    if user:
        auth.login(request,user)    # 登录存储session信息
        return Response(data={'msg':'login success','to':'index.html'},status=status.HTTP_302_FOUND)    # 登录成功后页面重定向到index页面
    return Response(data={'msg': 'error', 'retcode': status.HTTP_400_BAD_REQUEST, 'error': serializer.errors},status=status.HTTP_400_BAD_REQUEST)   # 失败返回错误信息


@api_view(['GET'])
@permission_classes(())
def logout(request):
    # 当前用户处于登录状态
    if request.user.is_authenticated:
        auth.logout(request)    # 清除登录信息
    return Response(data={'msg': 'logout', 'to': 'login.html'},status=status.HTTP_302_FOUND)    # 重定向到登录页面


@api_view(['GET'])
@permission_classes(())
def current_user(request):
    # 如果当前用户处于登录状态
    if request.user.is_authenticated:
        serializer = UserSerializer(request.user)
        # 返回当前用户信息
        return Response(data=serializer.data)
    else:
        return Response(data={'msg': '用户未登录', 'retcode': status.HTTP_403_FORBIDDEN, 'to': 'login.html'},status=status.HTTP_403_FORBIDDEN)   # 重定向到登录页面

DRF的认证是在定义有权限类(permission_classes)的视图下才有作用,且权限类(permission_classes)必须要求认证用户才能访问此视图。如果没有定义权限类(permission_classes),那么也就意味着允许匿名用户的访问,自然牵涉不到认证相关的限制了。

对视图集禁用全局认证,也可以通过这种方式。

修改sqtp应用目录下的views.py文件中的ProjectViewSet视图集

from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.permissions import IsAuthenticated

class ProjectViewSet(viewsets.ModelViewSet):
    queryset = Project.objects.all()
    serializer_class = ProjectSerializer
    # 权限--使用空元组,不使用全局认证
    authentication_classes = (())
    permission_classes = (())

DRF权限方案

一般在项目中的使用方式是在全局配置 DEFAULT_AUTHENTICATION_CLASSES 认证,然后会定义多

base views,根据不同的访问需求来继承不同的base views即可

扩展下权限的范围,新增功能,只有当前项目的管理员才有读写当前项目的权限

定义权限

sqtp应用目录下新建permissions.py文件

from rest_framework import permissions

# 自定义权限类

class IsOwnerOrReadOnly(permissions.BasePermission):
    # 自定义权限只允许对象的所有者编辑它
    def has_object_permission(self, request, view, obj):
        #   读取权限允许任何请求
        if request.method in permissions.SAFE_METHODS:
            return True
        #   当前用户是否属于该项目管理员
        return obj.owner == request.user
加入权限

sqtp应用目录下的views.py文件中对ProjectViewSet视图类进行修改

from sqtp.permissions import IsOwnerOrReadOnly

class ProjectViewSet(viewsets.ModelViewSet):
    queryset = Project.objects.all()
    serializer_class = ProjectSerializer
    # 权限
    authentication_classes = ((SessionAuthentication, BasicAuthentication))
    permission_classes = ((IsAuthenticated,IsOwnerOrReadOnly))

使用非当前项目的管理员用户进行修改测试,发现被拒绝

{
 "msg": "error",
 "retcode": 403,
 "error": "You do not have permission to perform this action."
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值