zoukankan      html  css  js  c++  java
  • 【Django学习】python测试开发djangorestframework61.权限认证(permission)

    前言

    用户登录后,才有操作当前用户的权限,不能操作其它人的用户,这就是需要用到权限认证,要不然你登录自己的用户,去操作别人用户的相关数据,就很危险了。

    • authentication是身份认证,判断当前用户的登录方式是哪种认证方式
    • permissions 是权限认证,判断哪些用户有操作权限

    authentication身份认证

    身份验证是将收到的请求和一组标识证书(如用户名密码、令牌)进行关联的一种机制,以便权限和策略可以根据这个标识证书来决定是否允许该请求。因此,身份验证发生在验证权限和限制检查之前。

    当收到的请求通过身份验证时:

    • request.user属性会设置为django.contrib.auth.User对象,即我们登录的对象(我们定义用户继承于User)。

    • request.auth会设置为对应的Token(如果带有Token)或者None(如果不带有Token)。
      当收到请求身份验证失败时:

    • request.user属性会设置为django.contrib.auth.models.AnonymousUser对象。

    • request.auth会设置为None。

    django rest framework权限和认证有四种方式:

    • BasicAuthentication 此身份验证方案使用HTTP基本身份验证,根据用户的用户名和密码进行签名。基本身份验证通常仅适用于测试
    • TokenAuthentication 此身份验证方案使用基于令牌的简单HTTP身份验证方案。令牌认证适用于客户端 - 服务器设置,例如本机桌面和移动客户端。
    • SessionAuthentication 此身份验证方案使用Django的默认会话后端进行身份验证。会话身份验证适用于与您的网站在同一会话上下文中运行的AJAX客户端。
    • RemoteUserAuthentication 此身份验证方案允许您将身份验证委派给Web服务器,该服务器设置REMOTE_USER 环境变量。

    permission权限认证

    权限检查通常使用request.user和request.auth属性中的身份验证信息来确定是否应允许传入请求。

    当权限检查失败时,将根据以下规则返回HTTP 403 Forbidden或HTTP 401 Unauthorized:

    • 如果收到的请求身份验证通过,但是权限验证失败,则返回HTTP 403 Forbidden;
    • 如果收到的请求身份验证失败,且最高优先级验证类不能使用WWW-Authenticate请求头,则返回HTTP 403 Forbidden;
    • 如果收到的请求身份验证失败,且最高优先级验证类可以使用WWW-Authenticate请求头,则返回HTTP 401 Unauthorized

    权限级别也有四种

    • AllowAny 允许所有用户
    • IsAuthenticated 表示仅仅允许身份验证通过的用户访问,其他用户无法访问。
    • IsAdminUser 表示仅仅允许管理员用户访问,普通用户无法访问。
    • IsAuthenticatedOrReadOnly 表示仅仅允许身份验证通过的用户访问,或者只允许只读请求(GET请求)访问。

    相关配置

    在settings.py中,INSTALLED_APPS添加rest_framework和rest_framework.authtoken

    INSTALLED_APPS = [
        'apiapp',
        'rest_framework.authtoken',
        'rest_framework',
    ]
    

    REST_FRAMEWORK添加权限认证方式和身份认证方式

    REST_FRAMEWORK = {
        # 权限认证
        'DEFAULT_PERMISSION_CLASSES': (
            'rest_framework.permissions.IsAuthenticated',            # IsAuthenticated 仅通过认证的用户
            'rest_framework.permissions.AllowAny',                   # AllowAny 允许所有用户
            'rest_framework.permissions.IsAdminUser',                # IsAdminUser 仅管理员用户
            'rest_framework.permissions.IsAuthenticatedOrReadOnly',  # IsAuthenticatedOrReadOnly 认证的用户可以完全操作,否则只能get读取
        ),
        # 身份认证
        'DEFAULT_AUTHENTICATION_CLASSES': (
            'rest_framework.authentication.BasicAuthentication',
            'rest_framework.authentication.SessionAuthentication',
            'rest_framework.authentication.TokenAuthentication',  # token认证
        )
    }
    

    登录生成token

    登录的时候,不需要身份认证,permission_classes设置成AllowAny,允许所有的用户

    permission_classes = (AllowAny,) # AllowAny 允许所有用户

    from django.http import JsonResponse
    from django.shortcuts import HttpResponse
    from rest_framework.authtoken.models import Token
    from django.contrib import auth
    from rest_framework.views import APIView
    from rest_framework import viewsets
    from rest_framework import serializers
    from .models import *
    from django.http import QueryDict
    from rest_framework.request import Request
    from rest_framework.permissions import IsAuthenticated,AllowAny
    from rest_framework.authentication import TokenAuthentication
    
    '''作者:上海悠悠,QQ交流群:750815713'''
    
    class LoginViewSet(APIView):
        '''登录获取token方法'''
        permission_classes = (AllowAny,)      # AllowAny 允许所有用户
    
        def post(self, request, *args, **kwargs):
            username = request.data.get('username')
            # print(username)
            password = request.data.get('password')
            user = auth.authenticate(username=username, password=password)
            if not user:
                return HttpResponse({"code": 0,
                                    "msg": "用户名或密码不对!"})
            # 删除原有的Token
            old_token = Token.objects.filter(user=user)
            old_token.delete()
            # 创建新的Token
            token = Token.objects.create(user=user)
            return JsonResponse({"code": 0,
                                 "msg": "login success!",
                                 "username": user.username,
                                 "token": token.key})
    

    添加card相关信息,接着前面一篇讲的,添加authentication_classes和permission_classes

    authentication_classes = (TokenAuthentication,) # token认证
    permission_classes = (IsAuthenticated,) # # IsAuthenticated 仅通过认证的用户

    def get_parameter_dic(request, *args, **kwargs):
        # 作者:上海悠悠,QQ交流群:750815713
        if isinstance(request, Request) == False:
            return {}
    
        query_params = request.query_params
        if isinstance(query_params, QueryDict):
            query_params = query_params.dict()
        result_data = request.data
        if isinstance(result_data, QueryDict):
            result_data = result_data.dict()
    
        if query_params != {}:
            return query_params
        else:
            return result_data
    
    
    class CardSerializer(serializers.HyperlinkedModelSerializer):
        class Meta:
            model = Card
            fields = "__all__"
    
    class CardViewSet(viewsets.ModelViewSet):
        '''# 作者:上海悠悠,QQ交流群:750815713'''
        authentication_classes = (TokenAuthentication,)   # token认证
        permission_classes = (IsAuthenticated,)  # # IsAuthenticated 仅通过认证的用户
        queryset = Card.objects.all()
        serializer_class = CardSerializer
    
        def get(self, request, *args, **kwargs):
            params=get_parameter_dic(request)
            return JsonResponse(data=params)
    
        def post(self, request, *args, **kwargs):
            params=get_parameter_dic(request)
            return JsonResponse(data=params)
    
        def put(self, request, *args, **kwargs):
            params=get_parameter_dic(request)
            return JsonResponse(data=params)
    

    models.py设计card表

    class Card(models.Model):
        '''银行卡 基本信息 # 作者:上海悠悠,QQ交流群:750815713'''
        card_id = models.CharField(max_length=30, verbose_name="卡号", default="")
        card_user = models.CharField(max_length=10, verbose_name="姓名", default="")
        add_time = models.DateField(auto_now=True, verbose_name="添加时间")
    
        class Meta:
            verbose_name_plural = '银行卡账户'
            verbose_name = "银行卡账户_基本信息"
            
        def __str__(self):
            return self.card_id
    

    urls.py添加方法地址

    from apiapp import views
    from django.conf.urls import url
    from rest_framework import routers
    from django.conf.urls import include
    
    # 作者:上海悠悠,QQ交流群:750815713
    
    router = routers.DefaultRouter()
    router.register(r'cards', views.CardViewSet)
    
    urlpatterns = [
        url(r'^api/v1/login/$', views.LoginViewSet.as_view()),
        url(r'^', include(router.urls)),
    ]
    

    测试接口

    先获取登录token,把token值复制出来:1c0debb44fa0054d312616e7000ae78ce396df8e

    {
    	"code": 0,
    	"msg": "login success!",
    	"username": "test",
    	"token": "1c0debb44fa0054d312616e7000ae78ce396df8e"
    }
    

    访问添加银行卡账号的接口时,需在头部带上token,格式为

    Authorization: Token 1c0debb44fa0054d312616e7000ae78ce396df8e

    带上token去请求的时候,就可以正常的添加成功

    查看数据库card表会有数据新增成功

    如果token错误,或者没有token就会出现401 Unauthorized

    转载:https://www.cnblogs.com/yoyoketang/p/11518524.html

    作者:gtea 博客地址:https://www.cnblogs.com/gtea
  • 相关阅读:
    圆环自带动画进度条ColorfulRingProgressView
    FragmentTabHost+FrameLayout实现底部菜单栏
    PopupWindowFromBottom 从底部弹出popupwindow
    Android滚动选择控件
    github入门基础之上传本地文件以及安装github客户端
    Android 快速开发系列 ORMLite 框架最佳实践之实现历史记录搜索
    Android 快速开发系列 ORMLite 框架最佳实践
    《Entity Framework 6 Recipes》中文翻译——第十章EntityFramework存储过程处理(一)
    《Entity Framework 6 Recipes》中文翻译——第九章EntityFramework在N层架构程序中的应用(七)
    《Entity Framework 6 Recipes》中文翻译——第九章EntityFramework在N层架构程序中的应用(六)
  • 原文地址:https://www.cnblogs.com/gtea/p/15573700.html
Copyright © 2011-2022 走看看