日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > vue >内容正文

vue

10- vue django restful framework 打造生鲜超市 -用户登录和手机注册(中)

發(fā)布時(shí)間:2023/12/15 vue 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 10- vue django restful framework 打造生鲜超市 -用户登录和手机注册(中) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Vue+Django REST framework實(shí)戰(zhàn)

搭建一個(gè)前后端分離的生鮮超市網(wǎng)站
Django rtf 完成 手機(jī)注冊和用戶登錄(中)

Json Web Token的原理

因?yàn)槲覀兊膁rf 的token auth有它的缺點(diǎn)。所以最常用的還是JWT的方式

以下內(nèi)容轉(zhuǎn)載于: http://lion1ou.win/2017/01/18/

http是一種無狀態(tài)的協(xié)議,前后兩次請求它會(huì)不知道這是從同一個(gè)人還是不同的人發(fā)的。

傳統(tǒng)方式: 采用session和cookie結(jié)合的方式

前后端分離的傳統(tǒng): 用戶信息生成token token 和對于的用戶id保存到數(shù)據(jù)庫或session中。我們的drf 的 token auth 就是這種。

接著把token傳給用戶,存入瀏覽器cookie。之后的請求帶上這個(gè)cookie,后端根據(jù)這個(gè)cookie值查詢用戶,驗(yàn)證過期的邏輯需要表里多一個(gè)字段,以及后端的邏輯驗(yàn)證。

問題: xss漏洞: cookie可以被js讀取。作為后端識(shí)別用戶的標(biāo)識(shí),cookie的泄露意味著用戶信息不再安全。特別是drf我們的token auth沒有過期時(shí)間

設(shè)置cookie時(shí)兩個(gè)更安全的選項(xiàng): httpOnly以及secure項(xiàng).

  • httponly的不能被js讀取,瀏覽器會(huì)自動(dòng)加在請求header中
  • secure就只通過https

httponly 問題。很容易被xsrf攻擊,因?yàn)閏ookie會(huì)默認(rèn)發(fā)出去。

如果將驗(yàn)證信息保存數(shù)據(jù)庫。每次都要查詢。保存session,加大了服務(wù)器端存儲(chǔ)壓力。

那我們可以不要服務(wù)器去查詢呢?

只要我們生成的token遵循一定的規(guī)律,比如使用對稱加密算法來加密id 形成token。
服務(wù)端只需要解密token 就能知道id。

  • 這樣做的問題在于如果他知道你是怎么加密的。那么它可以通過這種加密方式偽造token

此時(shí)我們使用非對稱加密算法。

對稱加密,加密和解密使用的是同一個(gè)密鑰。服務(wù)器把token傳給用戶,以及用戶拿著token來服務(wù)器進(jìn)行解密。加密解密都在服務(wù)器端。

JWT 是一個(gè)開放標(biāo)準(zhǔn)(RFC 7519),它定義了一種用于簡潔,自包含的用于通信雙方之間以 JSON 對象的形式安全傳遞信息的方法。JWT 可以使用 HMAC 算法或者是 RSA 的公鑰密鑰對進(jìn)行簽名。它具備兩個(gè)特點(diǎn)

  • 簡潔(Compact)

可以通過URL, POST 參數(shù)或者在 HTTP header 發(fā)送,因?yàn)閿?shù)據(jù)量小,傳輸速度快

  • 自包含(Self-contained)

負(fù)載中包含了所有用戶所需要的信息,避免了多次查詢數(shù)據(jù)庫

mark

頭部包含兩部分,token和加密算法。會(huì)進(jìn)行Base64加密。但是會(huì)很容易反解出來

  • Header 頭部

頭部包含了兩部分,token 類型和采用的加密算法

{"alg": "HS256","typ": "JWT" }

它會(huì)使用 Base64 編碼組成 JWT 結(jié)構(gòu)的第一部分。

  • Payload 負(fù)載

這部分就是我們存放信息的地方了,你可以把用戶 ID 等信息放在這里,JWT 規(guī)范里面對這部分有進(jìn)行了比較詳細(xì)的介紹,常用的由 iss(簽發(fā)者),exp(過期時(shí)間),sub(面向的用戶),aud(接收方),iat(簽發(fā)時(shí)間)。

{"iss": "lion1ou JWT","iat": 1441593502,"exp": 1441594722,"aud": "www.example.com","sub": "lion1ou@163.com" }

同樣的,它會(huì)使用 Base64 編碼組成 JWT 結(jié)構(gòu)的第二部分

  • Signature 簽名

前面兩部分都是使用 Base64 進(jìn)行編碼的,即前端可以解開知道里面的信息。Signature 需要使用編碼后的 header 和 payload 以及我們提供的一個(gè)密鑰,然后使用 header 中指定的簽名算法(HS256)進(jìn)行簽名。簽名的作用是保證 JWT 沒有被篡改過。

可以解開就是指前端可以通過token拿到用戶的一部分非敏感信息。

JWT不會(huì)再保存數(shù)據(jù)了。a關(guān)注b,發(fā)郵件給b。b直接點(diǎn)擊帶回來串和action。就不需要登錄了。

設(shè)計(jì)用戶認(rèn)證和授權(quán)系統(tǒng)(獨(dú)立),以及單點(diǎn)登錄。

mark

單點(diǎn)登錄,多個(gè)子域名通過一個(gè)統(tǒng)一的授權(quán)認(rèn)證接口進(jìn)行登錄。

https://github.com/GetBlimp/django-rest-framework-jwt

首先要安裝

pip install djangorestframework-jwt

使用:

需要將jsonWebAuth加入到drf 的default auth class中

'rest_framework_jwt.authentication.JSONWebTokenAuthentication',

對于用戶post過來的token進(jìn)行驗(yàn)證,將user取出來

  • path中的配置
from rest_framework_jwt.views import obtain_jwt_token #...urlpatterns = ['',# ...url(r'^api-token-auth/', obtain_jwt_token), ]

配置path中的jwt

# jwt的token認(rèn)證path('jwt-auth/', obtain_jwt_token ) mark mark curl -H "Authorization: JWT <your_token>" http://localhost:8000/protected-url/ mark

jwt的加密認(rèn)證方式可以參照jwt的源碼進(jìn)行學(xué)習(xí)。

vue和jwt接口調(diào)試

  • vue中登錄的邏輯
//登錄 export const login = params => {return axios.post(`${host}/login/`, params) }

vue中的登錄post到login接口

要么改前端,要么改后端,畢竟我們現(xiàn)在在寫后端。改后端url為login

# jwt的token認(rèn)證path('login/', obtain_jwt_token )

前往login.vue中查看登錄的具體邏輯

login({username:this.userName, //當(dāng)前頁碼password:this.parseWord}).then((response)=> {console.log(response);//本地存儲(chǔ)用戶信息cookie.setCookie('name',this.userName,7);cookie.setCookie('token',response.data.token,7)//存儲(chǔ)在store// 更新store數(shù)據(jù)that.$store.dispatch('setInfo');//跳轉(zhuǎn)到首頁頁面this.$router.push({ name: 'index'})})

獲取到當(dāng)前的用戶名和密碼 這個(gè)用戶名和密碼來自當(dāng)前的data()中

data中的值又通過v-model進(jìn)行了與輸入框中值的綁定(我猜的啊)

本地存儲(chǔ)設(shè)置了cookie的名字和值,token和值。并設(shè)置了7天過期

mark

可以看到我們的vue數(shù)據(jù)中已經(jīng)有了name 和 token

setInfo會(huì)進(jìn)行實(shí)時(shí)數(shù)據(jù)同步更新的操作

[types.SET_INFO] (state) {state.userInfo = {name:cookie.getCookie('name'),token:cookie.getCookie('token')}console.log(state.userInfo);},

我們的jwt 調(diào)用的是django自帶的auth與userProfile中數(shù)據(jù)進(jìn)行對比。而我們?nèi)绻褂檬謾C(jī)注冊,就會(huì)導(dǎo)致驗(yàn)證失敗。因?yàn)槟J(rèn)是用用戶名和密碼去查的。

自定義django用戶認(rèn)證函數(shù)

  • 首先在setting中設(shè)置變量:
  • # 設(shè)置郵箱和用戶名和手機(jī)號(hào)均可登錄 AUTHENTICATION_BACKENDS = ('users.views.CustomBackend',)
  • 在user/view中
  • class CustomBackend(ModelBackend):"""自定義用戶驗(yàn)證規(guī)則"""def authenticate(self, username=None, password=None, **kwargs):try:# 不希望用戶存在兩個(gè),get只能有一個(gè)。兩個(gè)是get失敗的一種原因# 后期可以添加郵箱驗(yàn)證user = User.objects.get(Q(username=username) | Q(mobile=username))# django的后臺(tái)中密碼加密:所以不能password==password# UserProfile繼承的AbstractUser中有def check_password(self,# raw_password):if user.check_password(password):return userexcept Exception as e:return None mark

    通過斷點(diǎn)測試可以成功的進(jìn)入了我們的這段邏輯。

    JWT的過期時(shí)間設(shè)置

    # 與drf的jwt相關(guān)的設(shè)置 JWT_AUTH = {'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=20),'JWT_AUTH_HEADER_PREFIX': 'JWT', }

    這里的header前綴我們要保持與前端的一致。

    src/axios/index.js:

    config.headers.Authorization = `Bearer ${store.state.userInfo.token}`;

    云片網(wǎng)發(fā)送短信驗(yàn)證碼

    注冊會(huì)用到一些高級的Serializer。

    寫一個(gè)接口:發(fā)送短信

    form的驗(yàn)證。

  • 云片網(wǎng)
  • 可以有很多子賬號(hào),每個(gè)子賬號(hào)都會(huì)有一個(gè)api key 這個(gè)api key就會(huì)很重要。

    發(fā)送短信驗(yàn)證碼這個(gè)key是必須要用到的。

    文本短信 & 語音短信

    發(fā)送國內(nèi)短信申請簽名。短信模板。

    • 新建簽名(審核), 新建模板(可包含變量,審核)

    api文檔中使用說明。

    國內(nèi)短信api文檔: https://www.yunpian.com/doc/zh_CN/domestic/list.html

    單條發(fā)送,批量發(fā)送(相同內(nèi)容,不同內(nèi)容)

    https://www.yunpian.com/doc/zh_CN/domestic/single_send.html

    參數(shù)。必填字段填過來。示例代碼

    utils下yunpian.py

    線上部署時(shí)一定要將自己服務(wù)器的ip加入ip白名單中。測試時(shí)搜索本機(jī)ip地址。

    # encoding: utf-8 __author__ = 'mtianyan' __date__ = '2018/3/8 0008 09:28' import json import requestsclass YunPian(object):def __init__(self, api_key):self.api_key = api_keyself.single_send_url = "https://sms.yunpian.com/v2/sms/single_send.json"def send_sms(self, code, mobile):parmas = {"apikey": self.api_key,"mobile": mobile,"text": "【慕學(xué)生鮮】您的驗(yàn)證碼是{code}。如非本人操作,請忽略本短信".format(code=code)}response = requests.post(self.single_send_url, data=parmas)re_dict = json.loads(response.text)return re_dictif __name__ == "__main__":yun_pian = YunPian("apikey的值")yun_pian.send_sms("2017", "手機(jī)號(hào)碼")

    注意text內(nèi)容必須要與后臺(tái)已申請過簽名并審核通過的模板保持一致

    drf實(shí)現(xiàn)發(fā)送短信驗(yàn)證碼接口

    # 發(fā)送驗(yàn)證碼是創(chuàng)建model中一條記錄的操作 from rest_framework.mixins import CreateModelMixin

    用戶傳過來的手機(jī)號(hào)碼我們要進(jìn)行兩次驗(yàn)證:

    • 是否有效
    • 有沒有被注冊過

    Serializer和django里的form modelform 是一樣的,所以這個(gè)驗(yàn)證我們把它放到我們的Serializer里面來做。

    • 為什么不像goods中一樣使用serializers.ModelSerializer

    因?yàn)槲覀僲odel中的code也是必填項(xiàng),而我們擁有的只有手機(jī)號(hào),所以會(huì)導(dǎo)致驗(yàn)證失敗

    setting.py中

    # 手機(jī)號(hào)碼正則表達(dá)式 REGEX_MOBILE = "^1[358]\d{9}$|^147\d{8}$|^176\d{8}$"

    users/serializers.py:

    # encoding: utf-8 __author__ = 'mtianyan' __date__ = '2018/3/8 0008 09:41' import re from datetime import datetime, timedelta from VueDjangoFrameWorkShop.settings import REGEX_MOBILE from users.models import VerifyCode from rest_framework import serializers from django.contrib.auth import get_user_model User = get_user_model()class SmsSerializer(serializers.Serializer):mobile = serializers.CharField(max_length=11)def validate_mobile(self, mobile):"""驗(yàn)證手機(jī)號(hào)碼(函數(shù)名稱必須為validate_ + 字段名)"""# 手機(jī)是否注冊if User.objects.filter(mobile=mobile).count():raise serializers.ValidationError("用戶已經(jīng)存在")# 驗(yàn)證手機(jī)號(hào)碼是否合法if not re.match(REGEX_MOBILE, mobile):raise serializers.ValidationError("手機(jī)號(hào)碼非法")# 驗(yàn)證碼發(fā)送頻率one_mintes_ago = datetime.now() - timedelta(hours=0, minutes=1, seconds=0)# 添加時(shí)間大于一分鐘以前。也就是距離現(xiàn)在還不足一分鐘if VerifyCode.objects.filter(add_time__gt=one_mintes_ago, mobile=mobile).count():raise serializers.ValidationError("距離上一次發(fā)送未超過60s")return mobile

    然后views中class SmsCodeViewset(CreateModelMixin, viewsets.GenericViewSet):

    重寫CreateModelMixin中的create方法

    原本的create方法

    def create(self, request, *args, **kwargs):serializer = self.get_serializer(data=request.data)serializer.is_valid(raise_exception=True)self.perform_create(serializer)headers = self.get_success_headers(serializer.data)return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    serializer.is_valid(raise_exception=True)有效性驗(yàn)證失敗會(huì)直接拋異常。
    被drf捕捉到返回400狀態(tài)碼。

    其中的APIKEY需要我們添加到setting.py中

    # 云片網(wǎng)設(shè)置 APIKEY = 'apikey值'

    生成四位數(shù)的驗(yàn)證碼值

    def generate_code(self):"""生成四位數(shù)字的驗(yàn)證碼"""seeds = "1234567890"random_str = []for i in range(4):random_str.append(choice(seeds))return "".join(random_str)

    改寫后的自定義方法:

    def create(self, request, *args, **kwargs):serializer = self.get_serializer(data=request.data)serializer.is_valid(raise_exception=True)mobile = serializer.validated_data["mobile"]yun_pian = YunPian(APIKEY)code = self.generate_code()sms_status = yun_pian.send_sms(code=code, mobile=mobile)if sms_status["code"] != 0:return Response({"mobile":sms_status["msg"]}, status=status.HTTP_400_BAD_REQUEST)else:code_record = VerifyCode(code=code, mobile=mobile)code_record.save()return Response({"mobile":mobile}, status=status.HTTP_201_CREATED) mark mark

    將返回的json在yunpian中l(wèi)oads成dict

    然后取出dict中的code和msg進(jìn)行判斷與返回。我們不需要向前端返回status。而是遵循restful api的規(guī)范。http狀態(tài)碼即可區(qū)分成功或失敗。消息并不代表。

    發(fā)送成功之后再保存驗(yàn)證碼

    調(diào)試是否正確

    調(diào)試之前配置好對應(yīng)的url

    from users.views import SmsCodeViewset # 配置codes的url router.register(r'codes', SmsCodeViewset, base_name="codes")

    http://127.0.0.1:8000/codes/

    mark mark

    返回中既設(shè)置了400的http code 又有和form類似的字段信息錯(cuò)誤

    字段名稱 : 數(shù)組(告訴你該字段的錯(cuò)誤)

    發(fā)送成功(201)

    mark

    總結(jié)

    以上是生活随笔為你收集整理的10- vue django restful framework 打造生鲜超市 -用户登录和手机注册(中)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。