django 使用channels 搭建websocket聊天程序

news/2024/4/26 19:53:07/文章来源:https://blog.csdn.net/ly1358152944/article/details/131511539

 channels官方文档:Django Channels — Channels 4.0.0 documentation

 效果如下:

 主要实现功能

基于Django的认证的群聊

具体实现

当建立websocket的时候,建立之前是http消息,我们可以拿到http消息里面的cookie等信息进行认证,本次使用的是jwt认证,因此需要在建立的连接的时候,将jwt认证信息通过cookie发送给后端,进行通信认证,具体方法如下:

from rest_framework_simplejwt.tokens import AccessToken
from django.http.cookie import parse_cookie
from rest_framework_simplejwt.authentication import JWTAuthenticationclass ServerAccessToken(AccessToken):"""自定义的token方法是为了登出的时候,将 access token 禁用"""def verify(self):user_id = self.payload.get('user_id')if BlackAccessTokenCache(user_id, hashlib.md5(self.token).hexdigest()).get_storage_cache():raise TokenError('Token is invalid or expired')super().verify()class CookieJWTAuthentication(JWTAuthentication):"""支持cookie认证,是为了可以访问 django-proxy 的页面,比如 flower"""def get_header(self, request):header = super().get_header(request)if not header:cookies = request.META.get('HTTP_COOKIE')if cookies:cookie_dict = parse_cookie(cookies)header = f"Bearer {cookie_dict.get('X-Token')}".encode('utf-8')return headerasync def token_auth(scope):cookies = scope.get('cookies')if cookies:token = f"{cookies.get('X-Token')}".encode('utf-8')if token:try:auth_class = CookieJWTAuthentication()validated_token = ServerAccessToken(token)return True, await sync_to_async(auth_class.get_user)(validated_token)except TokenError as e:return False, e.args[0]return False, False

然后再建立连接的时候,进行一个认证

class MessageNotify(AsyncJsonWebsocketConsumer):def __init__(self, *args, **kwargs):super().__init__(args, kwargs)self.room_group_name = Noneself.disconnected = Trueself.username = ""async def connect(self):status, user_obj = await token_auth(self.scope)if not status:logger.error(f"auth failed {user_obj}")# https://developer.mozilla.org/zh-CN/docs/Web/API/CloseEvent#status_codesawait self.close(4401)

具体群聊核心代码如下:

class MessageNotify(AsyncJsonWebsocketConsumer):def __init__(self, *args, **kwargs):super().__init__(args, kwargs)self.room_group_name = Noneself.disconnected = Trueself.username = ""async def connect(self):status, user_obj = await token_auth(self.scope)if not status:logger.error(f"auth failed {user_obj}")# https://developer.mozilla.org/zh-CN/docs/Web/API/CloseEvent#status_codesawait self.close(4401)else:logger.info(f"{user_obj} connect success")room_name = self.scope["url_route"]["kwargs"].get('room_name')username = self.scope["url_route"]["kwargs"].get('username')# data = verify_token(token, room_name, success_once=True)if username and room_name:self.disconnected = Falseself.username = usernameself.room_group_name = f"message_{room_name}"# Join room groupawait self.channel_layer.group_add(self.room_group_name, self.channel_name)await self.accept()else:logger.error(f"room_name:{room_name} token:{username} auth failed")await self.close()async def disconnect(self, close_code):self.disconnected = Trueif self.room_group_name:await self.channel_layer.group_discard(self.room_group_name, self.channel_name)# Receive message from WebSocketasync def receive_json(self, content, **kwargs):action = content.get('action')if not action:await self.close()data = content.get('data', {})if action == "message":data['uid'] = self.channel_namedata['username'] = self.username# Send message to room groupawait self.channel_layer.group_send(self.room_group_name, {"type": "chat_message", "data": data})else:await self.channel_layer.send(self.channel_name, {"type": action, "data": data})async def userinfo(self, event):data = {'username': self.username,'uid': self.channel_name}await self.send_data('userinfo', {'data': data})async def chat_message(self, event):data = event["data"]data['time'] = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')# Send message to WebSocketawait self.send_data('message', {'data': data})async def send_data(self, action, content, close=False):data = {'time': time.time(),'action': action}data.update(content)return await super().send_json(data, close)

中间还涉及消息队列,本次使用的是基于redis的消息队列,需要在settings.py进行配置

CHANNEL_LAYERS = {"default": {# "BACKEND": "channels_redis.core.RedisChannelLayer","BACKEND": "channels_redis.pubsub.RedisPubSubChannelLayer","CONFIG": {"hosts": [f"redis://:{REDIS_PASSWORD}@{REDIS_HOST}:{REDIS_PORT}/{CHANNEL_LAYERS_CACHE_ID}"],},},
}

代码已经开源,GitHub地址:GitHub - nineaiyu/xadmin-server: xadmin-基于Django+vue3的rbac权限管理系统

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_325543.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Elasticsearch实战(二十四)---ES数据建模一对多模型Nested结构

Elasticsearch实战—ES数据建模一对多模型Nested结构 文章目录 Elasticsearch实战---ES数据建模一对多模型Nested结构1.ES 一对多模型Nested 结构模型实战2.ES字段查询2.1 非Nested 错误结构及错误查询2.2 Nested结构,正确查询 3.Nested结构原理 我们如何把Mysql的模…

(0020) H5-Vue-router+Element-ui 搭建非常简单的dashboard

参考学习: Vue Vue-router Element-ui 搭建一个非常简单的dashboard demo demo参考:https://github.com/wangduanduan/vue-el-dashboard 在线预览 效果图: 使用到的技术: Vue Vue-router Element-ui webpack Normalize.css v…

Spring Boot 中的 @RefreshScope 注解是什么,原理,如何使用

Spring Boot 中的 RefreshScope 注解是什么,原理,如何使用 在 Spring Boot 中,RefreshScope 注解是一个非常有用的注解。它可以让 Spring Boot 应用程序在运行时重新加载配置。这意味着您可以在不停止和重新启动应用程序的情况下更改配置。在…

深入理解链表:一种动态的线性数据结构

文章目录 前言1. 概述2. 单向链表3. 单向链表(带哨兵)4. 双向链表(带哨兵)5. 环形链表(带哨兵)6. 结语 前言 链表是我们在日常编程中经常使用的一种数据结构,它相比于数组具有更好的动态性能。…

策略模式深度实践——通用的HTTP接口调用

个人主页:金鳞踏雨 个人简介:大家好,我是金鳞,一个初出茅庐的Java小白 目前状况:22届普通本科毕业生,几经波折了,现在任职于一家国内大型知名日化公司,从事Java开发工作 我的博客&am…

HNU-小学期工训-STC-B案例测试作业

对于一些案例,这里列举一些 流水灯 八位数码管动态扫描 八位数码管流水灯(有BSP版本) 八位数码管滚动显示(有BSP版本) 可变亮度的数码管显示(有BSP版本) 扫描频率可改变的电子钟 按键消抖计数(有BSP版本) 三按键测试(有BSP版本) 霍尔磁场检测(有BSP版本) 数…

kubectl详解之声明式管理方法

目录 一、声明式管理方法二、资源配置清单的管理2.1 查看资源配置清单2.1 修改资源配置清单并应用2.1.1 离线修改2.1.2 在线修改 一、声明式管理方法 适合于对资源的修改操作 声明式资源管理方法依赖于资源配置清单文件对资源进行管理 资源配置清单文件有两种格式:…

【C++11】lambda表达式详解

目录 1.lambda引入 2.语法 3.捕捉列表详解 [ ] 不捕获任何外部变量 [] 捕获父作用域的所有变量的值,只读不可以修改 [&]捕获父作用域的所有变量的引用,可修改捕获的变量 [val] 只捕获指定的变量值,不可以修改 [&val] 只捕获外…

【中间件-Openjob】高性能任务调度框架Openjob简介及快速搭建

介绍基础基础信息任务调度框架对比 特性高可靠高性能定时调度分布式计算延迟任务工作流程权限管理告警监控跨语言 安装访问docker-compose安装在线访问 总结 介绍 一款分布式高性能任务调度框架,支持多种定时任务、延时任务、工作流设计、轻量级分布式计算、无限水平…

谈谈NLP中 大语言模型LLM的 思维链 Chain-of-Thought(CoT)

Chain-of-Thought(CoT) 1.介绍 在过去几年的探索中,业界发现了一个现象,在增大模型参数量和训练数据的同时,在多数任务上,模型的表现会越来越好。因而,现有的大模型LLM,最大参数量已经超过了千亿。 然而…

kong-dashboard安装

简介 kong-dashboard提供了UI界面操作和查看kong,可以进行api、consumers、plugins操作 官网:https://hub.docker.com/r/pgbi/kong-dashboard/ 安装 联网安装 [slviewDEMO:~]$ docker search kong-dashboard INDEX NAME …

【VB6|第19期】vb6通过COM组件操作Excel

日期:2023年7月3日 作者:Commas 签名:(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释:如果您觉得有所帮助,帮忙点个赞,也可以关注我,我们一起成长;如果有不对的地方&#xff…

【elementplus】解决el-table开启show-overflow-tooltip后,tooltip的显示会被表格边框遮挡的问题

如图所示: 原因: 1. el-table没有设置高度;2.就是被遮住了 解决: 方法一:给el-table设置高度 方法二: .el-table {overflow: visible !important;}如果不想给el-table设置高度,就直接使用方法二解决即可

MyBatisPlus基础知识

一、MyBatisPlus 1.MyBatisPlus入门案例与简介 这一节我们来学习下MyBatisPlus的入门案例与简介,这个和其他课程都不太一样,其他的课程都是先介绍概念,然后再写入门案例。而对于MyBatisPlus的学习,我们将顺序做了调整&#xff0…

初级保育员专业知识生活管理考试题库及答案

​本题库是根据最新考试大纲要求,结合近年来考试真题的重难点进行汇编整理组成的全真模拟试题,考生们可以进行专项训练,查漏补缺巩固知识点。本题库对热点考题和重难点题目都进行了仔细的整理和编辑,相信考生在经过了针对性的刷题…

JAVA开发( 腾讯云消息队列 RocketMQ使用总结 )

一、问题背景 之所以需要不停的总结是因为在java开发过程中使用到中间件实在太多了,久久不用就会慢慢变得生疏,有时候一个中间很久没使用,可能经过了很多版本的迭代,使用起来又有区别。所以还是得不断总结更新。最近博主就是在使用…

jenkins的环境搭建

jenkins 环境 安装 我之前使用war安装、安装比较简单、就是jenkins的 对应的插件不能下载下来、后来发现是版本的问题、使用docker-compose 安装、jenkins安装 插件很容易安装下来 1、安装jdk 解压jdk 配置环境变量 #set java environment JAVA_HOME/usr/local/jdk1.8.0_281…

blender 之点云渲染(论文渲图)

blender 之点云渲染(论文渲图) 一、导入点云1.新建2.导入点云3.位置移动&放大缩小 二、Geometry Nodes实体化点云1.新建节点2.实体化 三、给实体化点云添加材质四、设置渲染引擎更换为Cycles。 五、对准视角1.新建一个球2.创建相机视角跟踪3.将uv球挪…

二、Spring Cloud Eureka 简介、快速入门

注册发现中心 Eureka 来源于古希腊词汇,意为“发现了”。在软件领域, Eureka 是 Netflix 在线影片公司开源的一个服务注册与发现的组件,和其他 Netflix 公司的服务组件(例如负载均衡、熔断器、网关等) 一起&#xff0…

LLM prompt提示构造案例

参考: https://github.com/PlexPt/awesome-chatgpt-prompts-zh 吴恩达 prompt工程应用: https://www.bilibili.com/video/BV1No4y1t7Zn prompt构造案例代码 prompt """文本分类任务:将一段用户给外卖服务的评论进行分类…