1. 程式人生 > 實用技巧 >解決reguest.session獲取不到指定資訊問題(釘釘機器人實現發簡訊--webhook)

解決reguest.session獲取不到指定資訊問題(釘釘機器人實現發簡訊--webhook)

1 使用者模組梳理

1.1 註冊

我們在編寫註冊模組的時候,尤其是高負載的情況下,儘可能地不讀庫,會極大地提高我們的效能。可以採用唯一索引。

1.2 登入

在登入的時候,我們要有一個思想,單因子登入,雙因子登入和三因子登入

  • 單因子登入:傳統的驗證使用者名稱,密碼這種機制不安全(密碼為唯一登入,不安全)圖片驗證碼
  • 雙因子登入:需要東西來驗證,識別(簡訊,郵件)
  • 三因子登入:滑塊,面部識別,指紋驗證

1.3 webhook

  • 動向擴充套件

整體思路就是,通過webhook把驗證碼發給機器人,機器人在釘釘端告訴使用者這個碼是多少,使用者看到碼,把碼通過表單形式,然後django端作對比,判斷是否登入成功。

2 所遇到的問題

2.1 設定釘釘機器人問題

  • 重要的地方(一)---> 加簽

  • 重要的地方(二)---> 獲取webhook

2.2 session問題

  • 非常可氣,postman除錯十分正常,但是瀏覽器沒有效果。

  • 根據自己的理解,寫了一個比較low的解決方案。

  • 由於採取的是session儲存,那就意味著,沒有辦法在獲取完驗證碼,request.session['key']=value 的情況下,在下一個檢視繼續獲取了。

3 程式碼例項

3.1 Django端

  • settings裡無需配置
3.1.1 views.py
from django.contrib.auth.hashers import make_password, check_password
from django.contrib.sessions.models import Session
from rest_framework.response import Response
from rest_framework.views import APIView
from userapp.models import UserModel
from userapp.utils import create_token, message_code, dingding_robot


class RegisterView(APIView):

    def post(self, request):
        username = request.data.get('username')
        password = request.data.get('password')
        tel = request.data.get('tel')
        try:
            user = UserModel.objects.create(username=username, password=make_password(password),tel=tel)
            token = create_token(user)
            return Response(
                {'msg': '註冊成功', 'code':200, 'token': token}
            )
        except Exception as e:
            print('異常', e)
            return Response(
                {'msg': '使用者名稱或手機號重複', 'code':400}
            )

class LoginView(APIView):

    def post(self, request):
        num = request.data.get('num')
        username = request.data.get('username')
        password = request.data.get('password')
        get_key = request.data.get('session_key')
        user = UserModel.objects.filter(username=username).first()
        if check_password(password, user.password):
            session_data = Session.objects.get(pk=get_key).get_decoded()
            num_get = session_data.get('num')
            if num == str(num_get):
                token = create_token(user)
                return Response(
                    {'msg': '登入成功', 'code': 200, 'token': token, 'num':num}
                )
        return Response(
            {'msg': '登入失敗', 'code': 400}
        )


class DingDingView(APIView):

    def get(self, request):
        num = message_code()
        dingding_robot(num)
        request.session['num'] = num
        request.session.set_expiry(300)
        if not request.session.session_key:
            request.session.create()
        return Response(
            {'msg': '傳送成功', 'code':200, 'num':num, 'session_key': request.session.session_key}
        )
3.1.2 utils.py
# -*- coding: utf-8 -*-
from rest_framework_jwt.settings import api_settings
def create_token(user):
    jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
    jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
    payload = jwt_payload_handler(user)
    token = jwt_encode_handler(payload)
    return token


def message_code():
    import random
    num = random.randint(100000, 999999)
    return num


def dingding_robot(num):
    import time
    import hmac
    import hashlib
    import base64
    import urllib.parse
    timestamp = str(round(time.time() * 1000))
    secret = 'SECc0cc53c0179ded46f9050ff40c8c767f2bd0f50a2e7255c1bc9afa014d246db2'
    secret_enc = secret.encode('utf-8')
    string_to_sign = '{}\n{}'.format(timestamp, secret)
    string_to_sign_enc = string_to_sign.encode('utf-8')
    hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
    sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
    import requests, json  # 匯入依賴庫
    headers = {'Content-Type': 'application/json'}  # 定義資料型別
    webhook = 'https://oapi.dingtalk.com/robot/send?access_token=2c3730563856be4f9dfc1ed8cfa1e1789c6ec88ba4964782529d4b866f503d1a&timestamp={}&sign={}'.format(timestamp,sign)
    data = {
        "msgtype": "text",
        "text": {"content": num},
        "isAtAll": True}
    res = requests.post(webhook, data=json.dumps(data), headers=headers)  # 傳送post請求
    return res

3.2 Vue端

3.2.1 Register.vue
<template>
    <div style="margin-top:200px">
        <center><h1 style="margin-top:50px">注&emsp;冊</h1></center>
        <div style="margin:0 auto;width:500px;height:200px">
            使用者名稱:
                <a-input placeholder="input your username" style="width:300px" v-model="username"/>
            <br>
            <br>
            密&ensp;&ensp;碼:
                <a-input-password placeholder="input your password" style="width:300px" v-model="password"/>
                <br>
                <br>
            手機號:
                <a-input placeholder="input your telphone" style="width:300px" v-model="tel"/>
                <br>
                <br>
              <a-button type="primary" @click="register">註冊</a-button>
        </div>
    </div>
</template>

<script>
import { user_register } from '@/http/apis'
export default {
    data() {
        return {
            username:'',
            password:'',
            tel:''
        }
    },
    methods: {
        register(){
            let register_data = {
                'username':this.username,
                'password': this.password,
                'tel':this.tel
            }
            user_register(register_data).then(res=>{
                // 已生成token,可以免登陸直接跳主頁的,後續寫
                res.code == 200?alert('註冊成功,即將跳轉登入介面')&this.$router.push('/login'):alert('請保證使用者名稱和手機號唯一哦')
            })
        }
    },
    created() {

    }
}
</script>

<style scoped>

</style>
3.2.2 Login.vue
<template>
    <div style="margin-top:200px">
        <center><h1 style="margin-top:50px">登&emsp;錄</h1></center>
        <div style="margin:0 auto;width:500px;height:200px">
            使用者名稱:
                <a-input placeholder="input your username" style="width:300px" v-model="username"/>
            <br>
            <br>
            密&ensp;&ensp;碼:
                <a-input-password placeholder="input your password" style="width:300px" v-model="password"/>
                <br>
                <br>
          <p>
              <a-input type="text" v-model="message_code"  style="width:200px"/>&emsp;<a-button type="primary"  @click="getMessageCode">釘釘獲取驗證碼</a-button>
          </p>
              <a-button type="primary" @click="login">登入</a-button>
        </div>
    </div>
</template>

<script>
import { get_message_code, user_login } from '@/http/apis'
export default {
    data() {
        return {
            username:'',
            password:'',
            message_code:'',
        }
    },
    methods: {
        // 獲取驗證碼
        getMessageCode(){
            get_message_code().then(res=>{
                console.log(res)
                res.code == 200?alert('獲取驗證碼成功')&sessionStorage.setItem('session_key', res.session_key):alert('失敗失敗')
            })
        },
        // 登入
        login(){
            let user_info = {
                'username':this.username,
                'password':this.password,
                'num':this.message_code,
                'session_key': sessionStorage.getItem('session_key')
            }
            user_login(user_info).then(
                res=>{
                   console.log(res) 
                   res.code == 200?alert('登入成功'):alert('登入失敗')
                }
            )
        }
    },
    created() {

    }
}
</script>

<style scoped>

</style>