一、基于jwt的多方式登陸
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.py
INSTALLED_APPS = [ ... 'rest_framework' ] #擴寫AUTH_USER表 AUTH_USER_MODEL = 'app01.UserInfo'
views.py
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=https://www.cnblogs.com/guojieying/archive/2020/11/12/request.data,context={'request':request}) ser = LoginSerializer(data=https://www.cnblogs.com/guojieying/archive/2020/11/12/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.py
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.py
from rest_framework.response import Response class APIResponse(Response): def __init__(self, code=100, msg='成功', data=https://www.cnblogs.com/guojieying/archive/2020/11/12/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=https://www.cnblogs.com/guojieying/archive/2020/11/12/dic, status=status, headers=headers, content_type=content_type)
urls.py
注意:自動生成路由,四種對應關系

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,password
二、自定義user表,簽發token,認證類的代碼實作多方式登錄
models.py
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.py
from rest_framework.response import Response class APIResponse(Response): def __init__(self, code=100, msg='成功', data=https://www.cnblogs.com/guojieying/archive/2020/11/12/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=https://www.cnblogs.com/guojieying/archive/2020/11/12/dic, status=status, headers=headers, content_type=content_type)
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()), ]
在自定義登錄的基礎上,加上自定義的認證,來查詢訂單資訊
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 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()), ]
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/226031.html
標籤:其他
上一篇:技術方案設計的方法
