DjangoRESTframework-用户状态校验
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."
}