1. 程式人生 > >Django REST framework - 認證

Django REST framework - 認證

憑據 設置 except token time 嘗試 failed Coding 身份驗證

目錄

  • 認證
    • DRF 5種驗證方式
    • 如何確定身份驗證?
    • 設置身份驗證方案
    • 案例: 基於自定義Token認證
      • 第一步: 定義一個用戶表和一個保存用戶Token的表
      • 第二步: 定義一個登陸視圖
      • 第三步定義一個認證類
      • 第四步: 使用認證類

認證

(我是誰?)

身份認證是將傳入請求與一組標識憑據相關聯的機制,然後,權限和限制策略可以使用這些憑據來確定是否應該允許該請求.

REST框架提供了許多開箱即用的身份驗證方案,還允許您實現自定義方案。
身份驗證始終在視圖的最開始,在發生權限和限制檢查之前,以及允許任何其他代碼繼續之前運行。

request.user 屬性通常將設置為contrib.authUser類的實例。

request.auth 屬性用於任何其他身份驗證信息,例如,它可用於表示請求已簽名的身份驗證令牌。

DRF 5種驗證方式

# 基於用戶名和密碼的認證
class BasicAuthentication(BaseAuthentication):
    pass

# 基於Session的認證
class SessionAuthentication(BaseAuthentication):
    pass

# 基於Tokend的認證
class TokenAuthentication(BaseAuthentication):
    pass

# 基於遠端用戶的認證(專用用戶管理服務器)
class TokenAuthentication(BaseAuthentication):
    pass

如何確定身份驗證?

身份驗證方案始終定義為類列表。REST框架將嘗試對列表中的每個類進行身份驗證,並將設置request.user和request.auth使用成功進行身份驗證的第一個類的返回值。

如果沒有類進行身份驗證,request.user則將設置為實例django.contrib.auth.models.AnonymousUser,request.auth並將其設置為None。

的價值request.user和request.auth對身份認證的請求可以通過修改UNAUTHENTICATED_USER和UNAUTHENTICATED_TOKEN設置。

設置身份驗證方案

  1. 可以使用該DEFAULT_AUTHENTICATION_CLASSES

    設置全局設置默認認證方案。例如

     REST_FRAMEWORK = {
         'DEFAULT_AUTHENTICATION_CLASSES': (
             'rest_framework.authentication.BasicAuthentication',
             'rest_framework.authentication.SessionAuthentication',
      )
     }
  2. 您還可以使用APIView基於類的視圖在每個視圖或每個視圖集的基礎上設置身份驗證方案。

     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` instance.
                 'auth': unicode(request.auth),  # None
             }
             return Response(content)
  3. 或者,如果您正在使用@api_view具有基於功能的視圖的裝飾器。

     @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` instance.
             'auth': unicode(request.auth),  # None
         }
         return Response(content)

案例: 基於自定義Token認證

第一步: 定義一個用戶表和一個保存用戶Token的表

class UserInfo(models.Model):
    username = models.CharField(max_length=16)
    password = models.CharField(max_length=32)
    type = models.SmallIntegerField(
        choices=((0, '普通用戶'), (1, 'VIP用戶')),
        default=0
    )


class Token(models.Model):
    user = models.OneToOneField(to='UserInfo')
    token_code = models.CharField(max_length=128)

第二步: 定義一個登陸視圖

from rest_framework.views import APIView
from app2 import models
from rest_framework.response import Response
import hashlib, time

def get_random_token(username):
    """
    根據用戶名和時間戳生成隨機token
    """
    timestamp = str(time.time())
    m = hashlib.md5(bytes(username, encoding="utf-8"))
    m.update(bytes(timestamp, encoding="utf-8"))
    return m.hexdigest()


class LoginView(APIView):
    """
    校驗用戶名是否正確從而生成token的視圖
    """
    def post(self, request):
        res = {"code": 0}
        # print(request.data)
        username = request.data.get("username")
        password = request.data.get("password")

        user = models.UserInfo.objects.filter(username=username, password=password).first()
        if user:
            token = get_random_token(username)
            models.Token.objects.update_or_create(defaults={"token_code": token}, user=user)
            res["token"] = token
        else:
            res["code"] = 1
            res["error"] = "用戶名或密碼錯誤"
        return Response(res)

第三步定義一個認證類

from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from app2 import models


class MyAuth(BaseAuthentication):
    def authenticate(self, request):
        # if request.method in ["POST", "PUT", "DELETE"]:  
        
        # 如果在表單中需要判斷請求方式    由於表單是post請求,所以獲取token 的方式為 request.data.get("token")
        # request.query_params為url中的參數
        request_token = request.query_params.get("token", None)  
        if not request_token:
            raise AuthenticationFailed('q.缺少token')

        token_obj = models.Token.objects.filter(token_code=request_token).first()
        if not token_obj:
            raise AuthenticationFailed("無效的Token")
        # token_obj.user 通過token這張表的對象和user這個關聯字段 找到 UserInfo表的對象及當前用戶對象
        return token_obj.user, request_token
        
        # else:
        #     return None, None

第四步: 使用認證類

視圖級別認證

# (用的不多)
class CommentViewSet(ModelViewSet):

    queryset = models.Comment.objects.all()
    serializer_class = app01_serializers.CommentSerializer
    authentication_classes = [MyAuth, ]

全局級別認證

# 在settings.py中配置
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.MyAuth", ]
}

Django REST framework - 認證