django rest framework 使用者認證
阿新 • • 發佈:2018-11-09
BaseAuthentication 類:
django rest framework 通過 BaseAuthentication 實現認證功能
無論是自定義的認證類還是 rest framework 自帶的認證類都應該繼承 BaseAuthentication
BaseAuthentication 中有兩個方法 authenticate 和 authenticate_header, 其中 authenticate 方法必須實現
如果使用者需要自定義認證方法則繼承 BaseAuthentication 重寫 authenticate 方法即可
models.py
from django.db import models class UserInfo(models.Model): user_type_choices = ( (1, '普通使用者'), (2, 'VPI'), (3, 'SVPI'), ) user_type = models.IntegerField(choices=user_type_choices) username = models.CharField(max_length=32, unique=True) password = models.CharField(max_length=64) class UserToken(models.Model): user = models.OneToOneField('UserInfo', models.CASCADE) token = models.CharField(max_length=64)
APP_DIR/utils/auth.py # 在和 views.py 同級的目錄建立 utils 包, 在 utils 中建立 auth.py 檔案, 將認證相關的程式碼放入其中
from rest_framework import exceptions from rest_framework.authentication import BaseAuthentication from app01 import models # 實現自定義的認證類 class Authtication(BaseAuthentication): def authenticate(self, request): # 這兒的 request 物件不是 django 原生的 request 而是 rest_framework 內部進行封裝過的 request # 使用 request._request 呼叫 django 原生的 request 物件 token = request._request.GET.get('token') # 檢查使用者的 token 是否合法 token_obj = models.UserToken.objects.filter(token=token).first() if not token_obj: # rest_framework 會在內部捕捉這個異常並返回給使用者認證失敗的資訊 raise exceptions.AuthenticationFailed('使用者認證失敗') # 在 rest_framework 內部會將這兩個欄位賦值給request以供後續呼叫 return (token_obj.user, token_obj)
views.py
from django.http import JsonResponse
from rest_framework.views import APIView
from app01.utils.auth import Authtication
import hashlib
import time
# 生成 token 字串
def md5(user):
ctime = str(time.time())
m = hashlib.md5(bytes(user, encoding='utf-8'))
m.update(bytes(ctime, encoding='utf-8'))
return m.hexdigest()
# 使用者登入
class AuthView(APIView):
def post(self, request):
ret = {'code':1000, 'msg':None}
try:
user = request._request.POST.get('username')
pwd = request._request.POST.get('password')
obj = models.UserInfo.objects.filter(username=user, password=pwd).first()
if not obj:
ret['code'] = 1001
ret['msg'] = "使用者名稱或密碼錯誤"
# 為登入使用者建立token
token = md5(user)
#存在更新 不存在建立
models.UserToken.objects.update_or_create(user=obj, defaults={'token':token})
ret['token'] = token
except:
ret['code'] = 1002
ret['msg'] = '請求異常'
return JsonResponse(ret)
# 業務程式碼
class Order(APIView):
# 註冊自定義的認證類, 可以有多個, 從左到右進行認證匹配
authentication_classes = [Authtication,]
def get(self, request):
# request.user 這個值等於 Authtication 返回的元組的第一個值
# request.auth 這個值等於 Authtication 返回的元組的第二個值
ret = {'code':1000, 'msg':None, 'data':None}
ret['data'] = '恭喜使用本系統'
return JsonResponse(ret)
rest_framework 內建的認證類:
BasicAuthentication # 基於瀏覽器實現的 Basic 認證, ftp 使用網頁登入時使用的就是 Basic 認證
SessionAuthentication # 基於 django 的 user.is_active 進行認證
TokenAuthentication # 簡單的基於 token 的認證
RemoteUserAuthentication # 簡單的遠端使用者認證實現
配置全域性生效的認證類和匿名使用者:
自定義的認證類如果每次都在指定的類中使用 authentication_classes 指定那麼就有可能出現大量的重複程式碼
我們可以通過全域性設定讓指定的認證類對繼承至 APIView 的所有類生效
settings.py
REST_FRAMEWORK = {
# 設定全域性生效的認證類(可以有多個)
# app01 為 django app 的名稱
# utils 為 app 目錄下面的 utils 目錄(這個目錄必須包含 __init__.py 檔案)
# auth 為 utils 目錄下面的 auth.py 檔案
# Authtication 為 auth.py 檔案裡面的 Authtication 類
# 這兒的設定其實就是使用 from ... import ... 的路徑
'DEFAULT_AUTHENTICATION_CLASSES': ["app01.utils.auth.Authtication",],
#匿名使用者配置
'UNAUTHENTICATED_USER': None, # 設定匿名使用者的使用者名稱, 預設為 AnonymousUser, 使用 request.user 檢視
'UNAUTHENTICATED_TOKEN': None, # 設定匿名使用者的 token, 預設為 None, 使用 request.auth 檢視
}
指定 View 類不使用全域性的認證類:
在不使用全域性認證類的 View 類中新增 authentication_classes = [] 或者 authentication_classes = ['xxxx']
# authentication_classes = [] 表示不使用認證
# authentication_classes = ['xxxx'], xxxx 表示當前類需要使用的認證類用於替換全域性類