如何编写通过ws://协议连接到聊天的用户的自定义身份验证?该用户在Django应用的另一侧,他是移动用户,通过移动应用中的ws://连接websocket。我试图用chrome扩展来测试websocket,但是它无法连接到我的websocket。我认为是因为身份验证。
在Django渠道文档中,它说:
如果您有一个自定义的身份验证方案,则可以编写一个自定义的中间件来解析详细信息,并将用户对象(或所需的任何其他对象)放入您的范围内。中间件被编写为可调用的方法,它采用了ASGI应用程序,并且包装它以返回另一个ASGI应用程序。大多数身份验证只能在范围内完成,因此您需要做的就是覆盖采用范围的初始构造函数,而不是运行事件的协程。 这是一个中间件的简单示例,该中间件只是从查询字符串中取出用户ID并使用该ID: 可以将相同的原理应用于通过非HTTP协议进行身份验证;例如,您可能要使用聊天协议中某人的聊天用户名将其转换为用户。
from django.db import close_old_connections
class QueryAuthMiddleware:
def __init__(self, inner):
# Store the ASGI application we were passed
self.inner = inner
def __call__(self, scope):
# Look up user from query string (you should also do things like
# check it's a valid user ID, or if scope["user"] is already populated)
user = User.objects.get(id=int(scope["query_string"]))
close_old_connections()
# Return the inner application directly and let it run everything else
return self.inner(dict(scope, user=user))
我需要做什么查询?我对该用户一无所知,实际上是匿名用户。
请帮助我。
答案 0 :(得分:0)
在此示例代码中,您可能必须使用以下命令打开websocket连接:
ws://SERVER:PORT/PATH?1
?
之后的所有内容都是查询字符串。在示例代码中,您的query_string必须是用户ID,例如1
。
您可以更改代码以使用不同的查询字符串。例如,您可以使用:
from urllib.parse import parse_qs
from django.db import close_old_connections
class QueryAuthMiddleware:
def __init__(self, inner):
# Store the ASGI application we were passed
self.inner = inner
def __call__(self, scope):
# Look up user from query string (you should also do things like
# check it's a valid user ID, or if scope["user"] is already populated)
query_string = parse_qs(self.scope['query_string'])
if b'user_id' in query_string:
user = User.objects.get(id=int(query_string[b'user_id'][0]))
close_old_connections()
else:
user = AnonymousUser
# Return the inner application directly and let it run everything else
return self.inner(dict(scope, user=user))
现在,您可以使用此uri了:
ws://SERVER:PORT/PATH?user_id=1
您必须确保具有ID的用户存在于数据库中。您还必须编写实际的身份验证代码。每个用户都可以使用任意用户ID连接到该应用程序。不需要密码或身份验证令牌。
答案 1 :(得分:0)
我也遇到了同样的问题,下面的代码片段对解决方案进行了一些研究:
假设您已定义User类。您想要通过查询对用户进行身份验证,同时与ws建立连接时发送查询。
我将通过渠道安装和配置,假设您已成功安装并配置了渠道。
QueryAuthMiddleware类,如下所示:
from channels.auth import AuthMiddlewareStack
from django.conf import LazySettings
from urllib import parse
from rest_socket.models import User
from urllib.parse import parse_qs
from urllib.parse import unquote, urlparse
from channels.auth import AuthMiddlewareStack
from django.contrib.auth.models import AnonymousUser
class QueryAuthMiddleware:
"""
QueryAuthMiddleware authorization
"""
def __init__(self, inner):
self.inner = inner
def __call__(self, scope):
query_string = parse_qs(scope['query_string']) #Used for querystring token url auth
headers = dict(scope['headers']) #Used for headers token url auth
print("qeurry", query_string)
if b'user' in query_string:
try:
user = query_string[b'user'][0].decode()
print("user", user)
existing = User.objects.filter(id=user).last()
print(existing)
if existing:
print("existinguser")
scope['user'] = existing
else:
scope["user"] ="no user found"
except User.DoesNotExist:
pass
return self.inner(scope)
QueryAuthMiddlewareStack = lambda inner: QueryAuthMiddleware(AuthMiddlewareStack(inner))
您的routing.py应该是这样的:
from channels.security.websocket import AllowedHostsOriginValidator
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import OriginValidator
from django.urls import path
import your_app.routing
from project.utils.auth import QueryAuthMiddlewareStack
application = ProtocolTypeRouter({
# (http->django views is added by default)
'websocket': QueryAuthMiddlewareStack(
URLRouter(
your_app.routing.websocket_urlpatterns
)
),
})
routing inside application:
websocket_urlpatterns = [
path("tasks/", consumers.Task)
]
以及您与jango-channels的ws连接:
<script>
var notification;
if (location.protocol === 'https:') {
notification = new WebSocket('wss://' + "window.location.host" + "/tasks"+ "/?user=id");
console.log("with htpps")
}
else {
notification = new WebSocket('ws://' + window.location.host + "/tasks"+ "/?userr=id");
console.log("htpp")
}
notification.onopen = function open() {
console.log('notification connection created for NotificationWebsocket.');
};
notification.onmessage = function message(event) {
var data = JSON.parse(event.data);
console.log("Socket response from NotificationWebsocket => ", data);
};
if (notification.readyState === WebSocket.OPEN) {
notification.onopen();
}
</script>