扫描登录功能

一、扫码登录功能

逻辑:

# 1 网站上,点击扫码登录---->弹出二维码
	-前端:向后端发送请求---->后端生成二维码--->返回--->前端显示了--->放了个链接地址
    -后端:生成二维码的接口
    
    
# 2 掏出手机,打开对应的app----->扫描二维码---->app能解析出这个地址---->取出你当前app登录的token---->向这个地址发送请求,携带token
	-后端有个携带token请求登录的接口
    	拿到请求传入的token,解析出当前用户---->签发token---->找个地方存着
    
# 3 网站上,开启了定时任务,不停的向后端发送请求---->查询有没有我让它签发token
	-一旦发现没有,过一会在发,3分钟内不停的发
    -用个唯一id号来检验,一旦发现有,携带回来--->token--->前端就登录成功了
    
    
    
 # 后端接口
	-1 生成二维码接口
    -2 手机携带token,得到用户,再签发token的接口
    -3 网站获取token接口
    
    
# 前端
	-二维码页面
    -定时任务

二、后端接口

路由

from .views import UserView, SckillView,QRlogin

router = SimpleRouter()
# /api/v1/user/qrlogin/scan/---->返回验证码
# /api/v1/user/qrlogin/login/--->前端一直发送请求接口
router.register('qrlogin', QRlogin, 'qrlogin')

urlpatterns = [
]

user/views.py

import qrcode  # 生成二维码的模块
import base64
from io import BytesIO
from django.core.cache import cache
from rest_framework.decorators import action
from rest_framework_jwt.settings import api_settings

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER


# 二维码登录接口
class QRlogin(ViewSet):
    @action(methods=['GET'], detail=False)
    # 生成二维码接口
    def scan(self, request, *args, **kwargs):
        # make生成二维码
        img = qrcode.make("http://192.168.1.252:8000/api/v1/user/qrlogin/login/?user_id=1")  # 地址后的唯一标识符应该动态获取,目前写死了
        img = img.get_image()  # 用二维码数据制作图像
        b = BytesIO()  # 想把数据保存在内存中,二进制数据
        img.save(b, format='JPEG')  # 把图片二进制放到了b中
        # b.getvalue() 取出二进制内容
        # 转成base64格式
        res = base64.b64encode(b.getvalue())
        # return APIResponse(url='data:image/jpg;base64,'+res)
        return APIResponse(url=res, user_id=1)

    @action(methods=['GET'], detail=False)
    def login(self, request, *args, **kwargs):
        # 签发token
        user_id = request.GET.get('user_id')
        user = User.objects.get(pk=user_id)
        # 签发token,存到redis
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)
        user_info = {'username': user.username, 'token': token}
        import time
        time.sleep(5)
        cache.set('user_id_%s' % user_id, user_info)
        return APIResponse()

    @action(methods=['GET'], detail=False)
    def check_login(self, request, *args, **kwargs):
        # 检查token接口
        user_id = request.GET.get('user_id')
        user_info = cache.get('user_id_%s' % user_id)
        if user_info:
            cache.set('user_id_%s' % user_id, None)
            return APIResponse(token=user_info.get('token'), username=user_info.get('username'))
        else:
            return APIResponse(code=101, msg='手机端尚未确认登录')

三、前端

router/index.js

import QRCodeLogin from "@/views/QRCodeLogin.vue";

const routes = [
    // ...
    {
        path: '/qrcode/login',  // 二维码登录
        name: 'qrcode',
        component: QRCodeLogin
    },
]

QRCodeLogin.vue

<template>
    <div>
        <img :src="url" alt="">
    </div>
</template>

<script>
export default {
    name: "QRCodeLogin",
    data() {
        return {
            url: '',
            user_id: '',
            t: null
        }
    },
    created() {
        this.$axios.get(`${this.$settings.BASE_URL}user/qrlogin/scan/`).then(res => {
            // 展示二维码
            this.url = 'data:image/jpg;base64,' + res.data.url
            this.user_id = res.data.user_id
            // 开启定时任务,向后端发送请求
            this.t = setInterval(() => {
                this.$axios.get(`${this.$settings.BASE_URL}user/qrlogin/check_login/?user_id=` + this.user_id).then(res => {
                    if (res.data.code === 100) {
                        this.$cookies.set('token', res.data.token, '7d')
                        this.$cookies.set('username', res.data.username, '7d')
                        clearInterval(this.t)
                        this.t = null
                        this.$router.push('/')
                    } else {
                        this.$message({
                            message: res.data.msg,
                            type: 'warning'
                        });
                    }
                })
            }, 3000)

            // 延时任务,3分钟后清除定时器
            setTimeout(()=>{
                clearInterval(this.t)
            }, 180000)
        })
    }
}
</script>

<style scoped>

</style>
posted @ 2023-07-14 14:51  星空看海  阅读(45)  评论(0编辑  收藏  举报