Django REST framework - 認證

認證

(我是誰?)api

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

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

request.user 屬性一般將設置爲contrib.authUser類的實例。框架

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

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使用成功進行身份驗證的第一個類的返回值。post

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

的價值request.user和request.auth對身份認證的請求能夠經過修改UNAUTHENTICATED_USER和UNAUTHENTICATED_TOKEN設置。rest

設置身份驗證方案

  1. 可使用該DEFAULT_AUTHENTICATION_CLASSES設置全局設置默認認證方案。例如code

    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", ]
}
相關文章
相關標籤/搜索