python測試開發django-61.許可權認證(permission)
- 2019 年 10 月 4 日
- 筆記
前言
用戶登錄後,才有操作當前用戶的許可權,不能操作其它人的用戶,這就是需要用到許可權認證,要不然你登錄自己的用戶,去操作別人用戶的相關數據,就很危險了。
- 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
