扫描登录功能
一、扫码登录功能
逻辑:
# 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>