1 手機號+密碼 用戶名+密碼 郵箱+密碼 2 流程分析(post請求): -路由:自動生成(推薦自動生成,本身手寫也行) -視圖類:ViewSet(ViewSetMixin, views.APIView) -序列化類:重寫validate方法,在這裏面對用戶名和密碼進行校驗
models.py----->進行數據遷移數據庫
from django.db import models from django.contrib.auth.models import AbstractUser class UserInfo(AbstractUser): phone = models.CharField(max_length=32, unique=True)
settings.pydjango
INSTALLED_APPS = [ ... 'rest_framework' ] #擴寫AUTH_USER表 AUTH_USER_MODEL = 'app01.UserInfo' REST_FRAMEWORK = { # 配置全局異常 'EXCEPTION_HANDLER': 'app01.utils.common_exception' }
views.pyjson
from rest_framework.viewsets import ViewSet from app01.serializer import LoginSerializer from app01.utils import APIResponse class LoginViewSet(ViewSet): def create(self, request, *args, **kwargs): # 實例化獲得一個序列化類的對象 # ser=LoginSerializer(data=request.data,context={'request':request}) ser = LoginSerializer(data=request.data) # 序列化類的對象的校驗方法 ser.is_valid(raise_exception=True) # 字段本身的校驗,局部鉤子校驗,全局鉤子校驗 # 若是經過,表示登陸成功,返回手動簽發的token token = ser.context.get('token') username = ser.context.get('username') return APIResponse(token=token, username=username) # 若是失敗,不用管了
serializer.pyapi
from rest_framework import serializers from app01.models import UserInfo import re from rest_framework.exceptions import ValidationError from rest_framework_jwt.utils import jwt_encode_handler, jwt_payload_handler class LoginSerializer(serializers.ModelSerializer): #重寫username否則報錯 username = serializers.CharField() class Meta: model = UserInfo fields = ['username', 'password'] def validate(self, attrs): # username多是郵箱,手機號,用戶名 username = attrs.get('username') password = attrs.get('password') # 若是是手機號 if re.match('^1[3-9]\d{9}$', username): # 以手機號登陸 user = UserInfo.objects.filter(phone=username).first() elif re.match('^.+@.+$', username): # 以郵箱登陸 user = UserInfo.objects.filter(email=username).first() else: # 以用戶名登陸 user = UserInfo.objects.filter(username=username).first() # 若是user有值而且密碼正確 if user and user.check_password(password): # 登陸成功,生成token # drf-jwt中有經過user對象生成token的方法 payload = jwt_payload_handler(user) token = jwt_encode_handler(payload) # token是要在視圖類中使用,如今咱們在序列化類中 # self.context.get('request') # 視圖類和序列化類之間經過context這個字典來傳遞數據 self.context['token'] = token self.context['username'] = user.username #必定要記得return return attrs else: raise ValidationError('用戶名或密碼錯誤')
utils.pyapp
from rest_framework.response import Response class APIResponse(Response): def __init__(self, code=100, msg='成功', data=None, status=None, headers=None, content_type=None, **kwargs): dic = {'code': code, 'msg': msg} if data: dic['data'] = data dic.update(kwargs) super().__init__(data=dic, status=status, headers=headers, content_type=content_type) from rest_framework.views import exception_handler #全局異常捕獲 def common_exception(exc, context): # 先調用REST framework默認的異常處理方法得到標準錯誤響應對象 response = exception_handler(exc, context) # 在此處補充自定義的異常處理 if response is None: response = Response(data={'code':999,'msg':str(exc)}) return response
urls.pypost
注意:自動生成路由,四種對應關係url
from django.urls import path from rest_framework.routers import SimpleRouter from app01 import views router = SimpleRouter() #必需要加,basename='login',否則會報錯 router.register('login', views.LoginViewSet,basename='login') print(router.urls) urlpatterns = [ ...
#path('login/', views.LoginViewSet.as_view({'post':'create'})), 能夠用這種本身手寫的路由 ] urlpatterns += router.urls
登陸方式:在http://127.0.0.1:8000/login/發送post請求,攜帶json格式username,passwordspa
models.pyrest
from django.db import models class MyUser(models.Model): username = models.CharField(max_length=32) #字段名必定要叫username否則要本身重寫,具體看源碼 password = models.CharField(max_length=32) phone = models.CharField(max_length=32) email = models.EmailField()
utils.pycode
from rest_framework.response import Response class APIResponse(Response): def __init__(self, code=100, msg='成功', data=None, status=None, headers=None, content_type=None, **kwargs): dic = {'code': code, 'msg': msg} if data: dic['data'] = data dic.update(kwargs) super().__init__(data=dic, status=status, headers=headers, content_type=content_type) from rest_framework.views import exception_handler #全局異常捕獲 def common_exception(exc, context): # 先調用REST framework默認的異常處理方法得到標準錯誤響應對象 response = exception_handler(exc, context) # 在此處補充自定義的異常處理 if response is None: response = Response(data={'code':999,'msg':str(exc)}) return response
views.py
from rest_framework.views import APIView from app01.utils import APIResponse import re from app01.models import MyUser from rest_framework_jwt.settings import api_settings jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER from rest_framework_jwt.views import obtain_jwt_token class MyLoginView(APIView): def post(self, request, *args, **kwargs): username = request.data.get('username') password = request.data.get('password') # 若是是手機號 if re.match('^1[3-9]\d{9}$', username): # 以手機號登陸 user = MyUser.objects.filter(phone=username).first() elif re.match('^.+@.+$', username): # 以郵箱登陸 user = MyUser.objects.filter(email=username).first() else: # 以用戶名登陸 user = MyUser.objects.filter(username=username).first() # 若是user有值而且密碼正確,注意這裏user.password == password if user and user.password == password: # 登陸成功,生成token # drf-jwt中有經過user對象生成token的方法 payload = jwt_payload_handler(user) token = jwt_encode_handler(payload) return APIResponse(token=token, username=user.username) else: return APIResponse(code=101, msg='用戶名或密碼錯誤')
urls.py
from django.contrib import admin from django.urls import path from app01 import views urlpatterns = [ path('login2/', views.MyLoginView.as_view()), ]
settings.py
INSTALLED_APPS = [ ... 'rest_framework' ] REST_FRAMEWORK = { # 配置全局異常 'EXCEPTION_HANDLER': 'app01.utils.common_exception' }
在自定義登陸的基礎上,加上自定義的認證,來查詢訂單信息
auth.py
from rest_framework_jwt.utils import jwt_decode_handler import jwt from rest_framework.exceptions import AuthenticationFailed from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication from app01.models import MyUser class JwtAuthentication(BaseJSONWebTokenAuthentication): def authenticate(self, request): token=request.META.get('HTTP_Authorization'.upper()) try: payload = jwt_decode_handler(token) except jwt.ExpiredSignature: raise AuthenticationFailed('過時了') except jwt.DecodeError: raise AuthenticationFailed('解碼錯誤') except jwt.InvalidTokenError: raise AuthenticationFailed('不合法的token') # 獲得的user對象,應該是本身user表的user對象 print(payload) # user=MyUser.objects.get(id=payload['user_id']) 這樣寫很差,會每次都查一次數據庫 user=payload #不用每次查數據庫
#或者user = MyUser(id=payload["user_id"], username = payload["username"])不用每次查數據庫
return (user, token)
views.py 加上如下認證代碼
from app01.auth import JwtAuthentication class OrderAPIView(APIView): authentication_classes = [JwtAuthentication, ] def get(self, request): # print(request.user) # 本身的user對象 print(request.user) # user是個字典,內部有user_id, # 後續要查詢該用戶的全部訂單,直接根據user_id查詢便可 return APIResponse(msg='查詢訂單成功')
urls.py
urlpatterns = [ path('order/', views.OrderAPIView.as_view()), ]