問題:有些API,須要用戶登陸才能訪問,有些無需登陸就能訪問。python
b. 登陸成功後保存在數據庫的UserToken表中數據庫
# urls.py from django.urls import path from api import views urlpatterns = [ path('api/v1/auth/',views.AuthView.as_view()), ] # views.py import hashlib, time from rest_framework.views import APIView from rest_framework.response import Response from api import models def md5(username): """ 生成token :param username: :return: """ m = hashlib.md5(username.encode('utf-8')) m.update(str(time.time()).encode('utf-8')) return m.hexdigest() class AuthView(APIView): """ 用戶登陸 """ def post(self, request, *args, **kwargs): ret = {'code': 1000, 'msg': None} username = request._request.POST.get('username') password = request._request.POST.get('password') user = models.UserInfo.objects.filter(username=username, password=password).first() if not user: ret['msg'] = '用戶名或密碼錯誤' return Response(ret) token = md5(username) # 存在就更新,不存在就建立 models.UserToken.objects.update_or_create(user=user, defaults={'token': token}) ret['code'] = 2000 ret['msg'] = '登陸成功' ret['token'] = token return Response(ret)
# urls.py urlpatterns = [ path('api/v1/auth/',views.AuthView.as_view()), path('api/v1/order/',views.OrderView.as_view()), ] # views.py ORDERS = [ { 'id': '1', 'name': '華爲MATE 20 Pro', 'price': 6999, }, { 'id': '2', 'name': '一加6t', 'price': 3999, }, { 'id': '3', 'name': '狗比亞', 'price': 2699, }, ] class Authentication(object): """ 自定義認證類 """ def authenticate(self, request): token = request._request.GET.get('token') token_obj = models.UserToken.objects.filter(token=token).first() if not token_obj: raise AuthenticationFailed('用戶認證失敗') # 返回一個元祖 一個是用戶對象。一個是token對象 return token_obj.user, token_obj def authenticate_header(self, request): pass class OrderView(APIView): """ 訂單相關業務 """ authentication_classes = [Authentication] def get(self, request, *args, **kwargs): ret = {'code': 2000, 'msg': '獲取成功', 'data': ORDERS} return Response(ret)
d. 測試接口:只測試了正確的用戶名和密碼,錯誤的本身測django
import requests auth_url = 'http://127.0.0.1:8000/api/v1/auth/' res = requests.post(auth_url, data={'username': 'alex', 'password': 'root1234'}).json() print(res) # {'code': 2000, 'msg': '登陸成功', 'token': '02fdedaa2c6c5773e00706b5890e289a'} token = res.get('token') order_url = 'http://127.0.0.1:8000/api/v1/order/' res = requests.get(order_url,params={'token':token}).json() print(res) # {'code': 2000, 'msg': '獲取成功', 'data': [{'id': '1', 'name': '華爲MATE 20 Pro', 'price': 6999}, {'id': '2', 'name': '一加6t', 'price': 3999}, {'id': '3', 'name': '狗比亞', 'price': 2699}]}
e. 再寫一個API用戶獲取用戶信息(經過認證經過後註冊的request.user對象和request.token對象)json
urlpatterns = [ path('api/v1/auth/',views.AuthView.as_view()), path('api/v1/order/',views.OrderView.as_view()), path('api/v1/user_info/',views.UserInfoView.as_view()), ] class UserInfoView(APIView): """ 獲取用戶信息相關 """ authentication_classes = [Authentication] def get(self, request, *args, **kwargs): data = { 'username': request.user.username, 'token': request.auth.token } ret = {'code': 2000, 'msg': '獲取成功', 'data': data} return Response(ret)
f. 測試認證成功以後返回元祖的兩個對象api
import requests auth_url = 'http://127.0.0.1:8000/api/v1/auth/' res = requests.post(auth_url, data={'username': 'alex', 'password': 'root1234'}).json() print(res) # {'code': 2000, 'msg': '登陸成功', 'token': '05810e2756bc6cc27c1ce3af827aa45f'} token = res.get('token') order_url = 'http://127.0.0.1:8000/api/v1/user_info/' res = requests.get(order_url,params={'token':token}).json() print(res) # {'code': 2000, 'msg': '獲取成功', 'data': {'username': 'alex', 'token': '05810e2756bc6cc27c1ce3af827aa45f'}}
def get_authenticators(self): return [auth() for auth in self.authentication_classes] authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES def reload_api_settings(*args, **kwargs): setting = kwargs['setting'] if setting == 'REST_FRAMEWORK': api_settings.reload() # 因此經過配置api.settings可達到全局使用的效果
# 在api應用下面建立utils\auth.py 把以前寫的自定義類剪切過來 # utils\auth.py from api import models from rest_framework.exceptions import AuthenticationFailed from rest_framework.authentication import BaseAuthentication class Authentication(BaseAuthentication): """ 自定義認證類 """ def authenticate(self, request): token = request._request.GET.get('token') token_obj = models.UserToken.objects.filter(token=token).first() if not token_obj: raise AuthenticationFailed('用戶認證失敗') # 返回一個元祖 一個是用戶對象。一個是token對象 return token_obj.user, token_obj def authenticate_header(self, request): pass # settings.py ##############rest_framework配置################ REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES':['api.utils.auth.Authentication'] } # views.py import hashlib, time from rest_framework.views import APIView from rest_framework.response import Response from api import models ORDERS = [ { 'id': '1', 'name': '華爲MATE 20 Pro', 'price': 6999, }, { 'id': '2', 'name': '一加6t', 'price': 3999, }, { 'id': '3', 'name': '狗比亞', 'price': 2699, }, ] def md5(username): """ 生成token :param username: :return: """ m = hashlib.md5(username.encode('utf-8')) m.update(str(time.time()).encode('utf-8')) return m.hexdigest() class AuthView(APIView): """ 用戶登陸 """ # 不須要認證爲空列表便可 authentication_classes = [] def post(self, request, *args, **kwargs): ret = {'code': 1000, 'msg': None} username = request._request.POST.get('username') password = request._request.POST.get('password') user = models.UserInfo.objects.filter(username=username, password=password).first() if not user: ret['msg'] = '用戶名或密碼錯誤' return Response(ret) token = md5(username) # 存在就更新,不存在就建立 models.UserToken.objects.update_or_create(user=user, defaults={'token': token}) ret['code'] = 2000 ret['msg'] = '登陸成功' ret['token'] = token return Response(ret) class OrderView(APIView): """ 訂單相關業務 """ def get(self, request, *args, **kwargs): ret = {'code': 2000, 'msg': '獲取成功', 'data': ORDERS} return Response(ret) class UserInfoView(APIView): """ 獲取用戶信息相關 """ def get(self, request, *args, **kwargs): data = { 'username': request.user.username, 'token': request.auth.token } ret = {'code': 2000, 'msg': '獲取成功', 'data': data} return Response(ret)
REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES":['api.utils.auth.FirstAuthtication','api.utils.auth.Authtication', ], #"UNAUTHENTICATED_USER":lambda :"匿名用戶", "UNAUTHENTICATED_USER":None, # 匿名,request.user = None "UNAUTHENTICATED_TOKEN":None,# 匿名,request.auth = None }
dispath()-->initialize_request()
- 封裝request對象,獲取認證類(全局&局部),經過列表生成式建立認證類對象post
認證成功基於反射根據method不一樣作不一樣處理測試