解决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>
posted @ 2020-12-16 20:04  狐狸大大爱吃糖  阅读(739)  评论(0编辑  收藏  举报