python測試開發django-rest-framework-61.權限認證(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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM