问题:有些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不一样作不一样处理测试