django - 如何通过 Django Channels 将 cookie 添加到标头?
问题描述
在我的前端,我有以下配置。身份验证是手动的,因为 react native 在持久会话时失败:
...
const authLink = setContext(request =>
storage.getCookie().then(cookie => ({
// Before the request is sent: set cookie header
headers: {
cookie,
},
credentials: 'omit', // set cookies manually
}))
)
const setTokenLink = new ApolloLink((operation, forward) => {
// Send the request to the server
return forward(operation).map(response => {
// After response is returned: store cookie in local storage
const context = operation.getContext()
const {
response: { headers },
} = context
if (headers) {
storage.setCookie(headers.get('set-cookie'))
}
return response
})
})
storage.getCookie().then(cookie => console.log(cookie))
// console.log('cookie', storage.getCookie().then(cookie => {cookie}))
const httpLink = createUploadLink({
uri: `${domainApi}/graphql/`,
})
const wsClient = new SubscriptionClient(
domainWs,
{
lazy: true,
reconnect: true,
connectionParams: {
authToken: storage.getCookie(),
},
})
)
...
然而,这似乎会影响 websockets,因为在后端,标头不包含 cookie。
class GraphqlSubcriptionConsumer(SyncConsumer):
def __init__(self, scope):
super().__init__(scope)
self.subscriptions = {}
self.groups = {}
def websocket_connect(self, message):
self.send({"type": "websocket.accept", "subprotocol": "graphql-ws"})
def websocket_disconnect(self, message):
for group in self.groups.keys():
group_discard = async_to_sync(self.channel_layer.group_discard)
group_discard(f"django.{group}", self.channel_name)
self.send({"type": "websocket.close", "code": 1000})
raise StopConsumer()
def websocket_receive(self, message):
request = json.loads(message["text"])
id = request.get("id")
if request["type"] == "connection_init":
return
elif request["type"] == "start":
print("scope user:", self.scope["user"]) //returns AnonymousUser
print("scope headers:", self.scope["headers"]) //returns headers without the cookie
...
有了这个配置,我得到
{'type': 'websocket.receive', 'text': '{"type":"connection_init","payload":{"authToken":{"_40":0,"_65":1,"_55":"sessionid=bci028bzn1cgxyuynvb7fjevc5ynqdil","_72":null}}}'}
在每条带有 type 的第一条消息中connection_init
。所以我想知道是否有一种方法可以手动将 django 中的 cookie(可能在 内部if request["type"] == "connection_init":
)插入范围,以便后续类型start
的消息包含 cookie。
任何小提示/提示都有帮助。
解决方案
要在服务器的握手响应中设置 cookie(用 测试channels==2.3.1
):
def connect(self): # connect method of your WebsocketConsumer
# called on connection
headers = {}
headers['Set-Cookie'] = 'myCookie=myValue'
self.accept(subprotocol=(None, headers))
一旦建立连接,就无法通过Set-Cookie
HTTP 响应标头将 cookie 从服务器发送到用户代理。那是因为它是一个开放的 TCP 套接字,协议不再是 HTTP。
Django Channels
autobahn
在引擎盖下使用。https://github.com/crossbario/autobahn-python/blob/9e68328df3c23ca3eee67017404235024f265693/autobahn/websocket/types.py#L285
推荐阅读
- swift - 'characters' 不可用:请直接使用字符串。我有这个问题
- ruby-on-rails - 如何将 QR 码存储在从 rqrcode 生成的 Rails 中
- r - 计算和分配变量的连续出现
- c# - 如何在另一个系统中安装exe?
- c# - 在 Visual Studio 中测试简单的 C# 代码表达式
- javascript - 如何使用相同的按钮设置多个输入字段的值
- perl - 如果不匹配推送到数组,则检查 perl 中 foreach 中的条件
- java - 将 websession 集群 WebSessionEntity 点燃到 HttpSession
- r - 在 R 中使用内存预分配循环读取/写入
- django - Django 管理员组权限在模板级别不起作用