参考了下别人说的原理,根据自己的逻辑实现,没有完全按照别人的原理来,所以不一定适用于大家,仅供参考吧!!!
流程如下:
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) break 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转发请求