如何在 Django 频道中使用 Django 的会话身份验证?



我正在使用Django、Django Channels和React开发一个国际象棋网络应用程序。我正在使用websocket进行在线玩家之间的游戏,并更新哪些玩家现在在线并可以玩。然而,我被身份验证部分卡住了。我首先从令牌身份验证开始,但我发现不可能将带有令牌的自定义标头作为websocket请求的一部分发送。然后我返回到默认的django.contrib.auth会话身份验证。不幸的是,当客户端登录并连接到websocket时,我无法获得他们的用户信息,就好像用户正在使用与websocket不同的会话一样。当我在websocket消费者中打印self.scope["user"]时,我得到值AnonymousUser。请注意,我可以使用websocket交换消息,身份验证可以很好地处理正常的http请求,因为我可以阻止未登录的用户访问视图。

我猜这个问题与客户端的websocket请求没有像http请求那样访问或使用cookie进行身份验证有关。

有人遇到过类似的问题吗?他们是如何解决的?

这就是我在react中发送websocket消息的方式:

submitMessage = (evt) => {
//console.log("token in Messenger=",this.props.token);
evt.preventDefault();
const message = { message: this.state.message_to_send}
this.ws.send(JSON.stringify(message))
}

这是用于处理websocket请求的后端代码:

from channels.generic.websocket import WebsocketConsumer
import json
from asgiref.sync import async_to_sync
class LoggedUsersConsumer(WebsocketConsumer):
def connect(self):
self.user = self.scope["user"]
print(self.scope)
print(self.user,"+++++++++++++")
#Join group
async_to_sync(self.channel_layer.group_add)(
"logged_users",
self.channel_name
)
self.accept()
def disconnect(self, close_code):
async_to_sync(self.channel_layer.group_discard)(
"logged_users",
self.channel_name
)
def receive(self, text_data):
self.user = self.scope["user"]
print(self.user,"+++++++++++++")
text_data_json = json.loads(text_data)
print(text_data_json)
message = text_data_json['message']
# Send message to room group
async_to_sync(self.channel_layer.group_send)(
"logged_users",
{
'type': 'logged_user_message',
'message': message
}
)
def logged_user_message(self, event):
message = event['message']
# Send message to WebSocket
self.send(text_data=json.dumps({
'message': message
}))

我认为你是对的,你可能没有用于客户端请求的会话cookie,这就是你得到AnonymousUser的原因。我认为这与如何处理React和Django中的websocket请求无关。

请在React前端(通过Chrome/Firefox中的开发工具(检查浏览器的cookie。你应该至少有两个cookie,csrftoken和sessionid。如果缺少其中任何一项,以下内容可能会帮助你朝着正确的方向前进。我在使用Vue、Django Channels和Django Rest Framework进行开发时也经历了同样的情况。

如果你通过浏览器访问Django后端,HTML模板和浏览器会负责设置cookie。当您从React或Vue执行此操作时,不会呈现HTML。因此,您需要自己实现身份验证和cookie设置。当然,您需要在稍后用于访问web套接字的同一会话中从React进行身份验证。

我使用以下Django视图从前端进行身份验证:

@api_view()
@permission_classes([AllowAny])
@ensure_csrf_cookie
@csrf_exempt
def session_info(request):
"""
View to retrieve user info for current user. (Can be adapted to your needs). If user is not logged in, view will
still return CSRF cookie which in neccessary for authentication.
"""
if not request.user.is_authenticated:
return Response({"message": "Not authenticated.", "authenticated": False})
return Response(
{"message": "Authenticated.", "authenticated": True, "user": str(request.user)}
)

@api_view(['POST'])
@permission_classes([AllowAny])
def session_auth(request):
"""
Login-view.
"""
username = request.data['username']
password = request.data['password']
user = authenticate(request, username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
request.session['authenticated_user'] = user.username
return Response(
{
"message": "Authenticated.",
"authenticated": True,
"name": user.name,
}
)
return Response({"message": "Not authenticated", "authenticated": False})

在urls.py中,您需要添加以下内容:

urlpatterns = [
path(
'session/',
views.session_info,
name='session',
),
path(
'sessionauth/',
views.session_auth,
name='sessionauth',
),
]

现在你可以在前端做这样的事情(下面是我的javascript/Vue代码,稍微适应了这篇文章,但你可能可以用React做类似的事情(:

// Please note: this code can probably be improved a lot as my skills in javascript are not the best
login: ({ username, password }) => {
window.$cookies.set("username", username);
const session_url = `${BACKEND_URL}/api/v1/session/`;
const url = `${BACKEND_URL}/api/v1/sessionauth/`;
axios.get(session_url).then(response => {      
axios.defaults.headers.common["Authorization"] = "";
// NOTE: the CSRF-cookie need to be included in subsequent POSTs:
axios.defaults.headers.post["X-CSRF-Token"] = response.data._csrf;
axios
.post(url, { username: username, password: password })
.then(response => {
axios.get(session_url);
})
.catch(e => {
console.log("ERROR: ", e);
commit("SET_LOGIN_ERROR", e);
});
});

我希望这能有所帮助。如果没有,请告诉我。

让我添加这个,以防它可能会帮助

您总是得到AnonymousUser,因为您可能没有正确传递cookie头。

使用会话身份验证,像这样传递会话头。

Cookie: csrftoken=wBD7Qri09dyAR8oMY8fuL1nqCOvGGmaO; sessionid=hpb8xx873holf3zl01wfe6f7511bhxqi

你可以试着做

Set-Cookie: sessionid=hpb8xx873holf3zl01wfe6f7511bhxqi;
Set-Cookie: csrftoken=wBD7Qri09dyAR8oMY8fuL1nqCOvGGmaO;

那行不通。

最新更新