Channels实现扫码登录

参考了下别人说的原理,根据自己的逻辑实现,没有完全按照别人的原理来,所以不一定适用于大家,仅供参考吧!!!

流程如下:

  1. web发起websocket链接,后端接受链接后立马发送第一次消息,消息为全局唯一标识key
  2. web收到第一次的消息,将key生成二维码展现出来
  3. App进行扫码获取key,并当做参数调用后端接口,成功则App提示用户

  3. 后端收到App的请求,成功处理(APP扫码成功)则向web发送第二次消息,为身份标识token,并关闭连接

  4. web收到token,存到本地,再做登录成功的逻辑,就o了

Django实现websocket的包目前只了解到channels跟dwebsocket,channels维护得比较好,功能也强大一些,所以采用channels了

具体在与web的通讯中,怎么判断App是否扫码了,我是这样做的(仅供参考):

  在后端生成key并第一次向web发送消息的时候,就存入将key存入redis,值为空。然后循环检测该值是否不为空,不为空就当做token发送给web,超时就提醒web。app扫码后调用后端接口时,后端就根据key将值设为身份token,前面循环检测到不为空,就...

当然,也可以去掉循环检测,让app也走websocket,把整体当做一个聊天室

下面展示主要代码

 跟Web通讯的代码:

from channels.generic.websocket import WebsocketConsumer
import time,random

redis_helper = RedisHelper()    # 自己的连接Redis工具类

# 扫码登录
class SaoLoginSync(WebsocketConsumer):
    redis_hash_name = 'sao_login'   # key存入redis1的hash结构名
    def connect(self):
        # 创建连接时调用
        self.accept()
        self.key = str(time.time()) + str(random.randint(0,9999))    # 用户id + 时间戳 + 随机数
        redis_helper.hset(self.redis_hash_name, self.key, '')
        self.send(text_data=self.key)  # key发给web生成二维码

        # 在此循环监听 app是否扫码了,扫码后吧生成的token发给web
        token = False
        start_time = time.time()
        while not token:
            token = redis_helper.hget(self.redis_hash_name, self.key)
            if token:
                self.send(text_data=token, close=True)
            if time.time() - start_time > 120:
                self.send(text_data='again', close=True)

    def disconnect(self, close_code):
        # 连接关闭时调用
        redis_helper.hdel(self.redis_hash_name, self.key)  # 删除key
        self.close()

App扫码之后调用的接口代码:

from rest_framework.decorators import api_view

# 扫码完成通知
@api_view(['POST'])
@login_verify   # 自己的登录验证装饰器,验证成功会加入user对象参数
def sao_code(request,user):
    key = request.POST.get('key')     # 扫码获取的key
    redis_hash_name = 'sao_login'   # key所在的hash结构名,与web通讯时一致
    platform = 'web'  # 平台
    redis_helper = RedisHelper()

    if redis_helper.hexists(redis_hash_name, key):  # 如果key存在
        # redis存token
        token = create_login_token(user.id, Platform[platform])
        login_key = Platform[platform] + '_login_token_' + str(user.id)
        redis_helper.set(login_key, token, ex=datetime.timedelta(days=30))    # 记录web的登录token
        redis_helper.hset(redis_hash_name, key, token)  # app 已经扫码完成,可以把token发送给web
        code, msg = (100, 'Sao successfully')
    else:
        code, msg = (-1, 'Key does not exist')

    return ret_CORS(code, msg)

对了, 正式部署到服务器的时候,channels得用daphne启动,然后最好配置一下由nginx转发请求

原文地址:https://www.cnblogs.com/MilletChili/p/9936850.html