Rest Framework:四、認證元件
阿新 • • 發佈:2018-12-18
一、建立LoginAuth類完成認證過程
urls.py
url(r'^login/', views.Login.as_view()), url(r'^books/', views.Books.as_view()),
models.py
from django.db import models # Create your models here. class UserInfo(models.Model): name = models.CharField(max_length=32) # 寫choice user_choice=((0,'普通使用者'),(1,'會員'),(2,'超級使用者')) # 指定choice,可以快速的通過數字,取出文字 user_type=models.IntegerField(choices=user_choice,default=0) pwd = models.CharField(max_length=32) class UserToken(models.Model): token = models.CharField(max_length=64) user = models.OneToOneField(to=UserInfo) class Book(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) price = models.DecimalField(max_digits=5, decimal_places=2) publish_date = models.DateField() publish = models.ForeignKey(to='Publish', to_field='nid', on_delete=models.CASCADE) authors = models.ManyToManyField(to='Author') def __str__(self): return self.name class Author(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) age = models.IntegerField() author_detail = models.OneToOneField(to='AuthorDatail', to_field='nid', unique=True, on_delete=models.CASCADE) class AuthorDatail(models.Model): nid = models.AutoField(primary_key=True) telephone = models.BigIntegerField() birthday = models.DateField() addr = models.CharField(max_length=64) class Publish(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) city = models.CharField(max_length=32) email = models.EmailField() def __str__(self): return self.name def test(self): return self.email
遷移資料庫
python3 manage makemigrations
python3 manage migrate
app01/MySerializer.py
from rest_framework import serializers from app01 import models class BookSerializer(serializers.ModelSerializer): class Meta: model = models.Book fields='__all__'
views.py
from django.shortcuts import render from django.http import JsonResponse from rest_framework.views import APIView from app01 import models import hashlib import time from django.core.exceptions import ObjectDoesNotExist from app01 import MySerializer # Create your views here. def get_token(name): # 生成一個md5物件 md5 = hashlib.md5() # 往裡新增值,必須是bytes格式 # time.time()生成時間戳型別,轉成字串,再encode轉成bytes格式 md5.update(str(time.time()).encode('utf-8')) md5.update(name.encode('utf-8')) return md5.hexdigest() class Login(APIView): authentication_classes = [] def post(self, request, *args, **kwargs): response = {'status': 100, 'msg': '登入成功'} name = request.data.get('name') pwd = request.data.get('pwd') try: user = models.UserInfo.objects.get(name=name, pwd=pwd) # 校驗通過,登入成功,生成一個隨機字串(身份標識)token token = get_token(name) # 儲存到資料庫 # update_or_create更新或者建立 models.UserToken.objects.update_or_create(user=user, defaults={'token': token}) response['token'] = token except ObjectDoesNotExist as e: response['status'] = 101 response['msg'] = '使用者名稱或密碼錯誤' except Exception as e: response['status'] = 102 # response['msg']='未知錯誤' response['msg'] = str(e) return JsonResponse(response, safe=False) from rest_framework import exceptions class LoginAuth(): # 函式名必須叫這個名字,接收必須兩個引數,第二個引數是request對像 def authenticate(self, request): # 從request對像中取出token (也可以從其他地方中取) token = request.query_params.get('token') # 去資料庫中查詢 ret = models.UserToken.objects.filter(token=token) if ret: # 可以查到,說明認證通過,返回空 return None # 否則會報異常 raise exceptions.APIException('認證失敗') from rest_framework.request import Request # class Books(APIView): # # 列表中型別不能加括號 # authentication_classes = [LoginAuth, ] # # def get(self, request, *args, **kwargs): # response = {'status': 100, 'msg': '查詢成功'} # # 必須登入以後,才能獲取資料 # # 取出token,取資料庫驗證,是否登入 # token = request.query_params.get('token') # ret = models.UserToken.objects.filter(token=token) # if ret: # # 認證通過,是登入使用者 # ret = models.Book.objects.all() # book_ser = MySerializer.BookSerializer(ret, many=True) # response['data'] = book_ser.data # else: # response['status'] = 101 # response['msg'] = '認證不通過' # return JsonResponse(response, safe=False) # 與上面的Books類功能一樣,但比上面的那個更加簡潔。 class Books(APIView): # 列表中型別不能加括號 authentication_classes = [LoginAuth, ] def get(self, request, *args, **kwargs): response = {'status': 100, 'msg': '查詢成功'} ret = models.Book.objects.all() book_ser = MySerializer.BookSerializer(ret, many=True) response['data'] = book_ser.data return JsonResponse(response, safe=False)
資料庫中新增資料測試:
使用Postman測試:
功能:登入後方可檢視書的詳情資訊
使用資料庫中的使用者名稱與密碼登入服務:
使用token登入來驗證查詢書的詳情資訊
若是token驗證不成功,就會返回:
二、認證元件的全域性使用與區域性使用
urls.py、models.py、不變
區域性使用:
views.py
from app01.MyAuth import LoginAuth class Books(APIView): # 列表中型別不能加括號 # 認證元件區域性使用 authentication_classes = [LoginAuth, ] # 認證元件,區域性禁用 authentication_classes = [] def get(self, request, *args, **kwargs): response = {'status': 100, 'msg': '查詢成功'} ret = models.Book.objects.all() book_ser = MySerializer.BookSerializer(ret, many=True) response['data'] = book_ser.data return JsonResponse(response, safe=False)
app01/MyAuth.py
from rest_framework import exceptions from app01 import models # 用dnf 認證,寫一個類 class LoginAuth(): # 函式名必須叫這個名字,接收必須兩個引數,第二個引數是request對像 def authenticate(self, request): # 從request對像中取出token (也可以從其他地方中取) token = request.query_params.get('token') # 去資料庫中查詢 ret = models.UserToken.objects.filter(token=token) if ret: # 可以查到,說明認證通過,返回空 return None # 否則會報異常 raise exceptions.APIException('認證失敗')
-全域性使用
-在setting中配置:
REST_FRAMEWORK={ 'DEFAULT_AUTHENTICATION_CLASSES':['app01.MyAuth.LoginAuth',], }
-區域性禁用,views.py中有:
認證元件,區域性禁用 authentication_classes = []