首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Django 3.0 +通道+ ASGI + TokenAuthMiddleware

Django 3.0 +通道+ ASGI + TokenAuthMiddleware
EN

Stack Overflow用户
提问于 2020-02-01 02:20:23
回答 2查看 1.6K关注 0票数 6

我升级到了Django 3.0,现在我在使用websockets +TokenAuthMiddleware时得到这个错误:

代码语言:javascript
复制
SynchronousOnlyOperation
You cannot call this from an async context - use a thread or sync_to_async.
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-02-01 02:20:23

问题是您不能从异步上下文访问同步代码。以下是Django 3.0的TokenAuthMiddleware

代码语言:javascript
复制
# myproject.myapi.utils.py
from channels.auth import AuthMiddlewareStack
from channels.db import database_sync_to_async
from django.contrib.auth.models import AnonymousUser

from rest_framework.authtoken.models import Token


@database_sync_to_async
def get_user(headers):
    try:
        token_name, token_key = headers[b'authorization'].decode().split()
        if token_name == 'Token':
            token = Token.objects.get(key=token_key)
            return token.user
    except Token.DoesNotExist:
        return AnonymousUser()


class TokenAuthMiddleware:

    def __init__(self, inner):
        self.inner = inner

    def __call__(self, scope):
        return TokenAuthMiddlewareInstance(scope, self)


class TokenAuthMiddlewareInstance:
    """
    Yeah, this is black magic:
    https://github.com/django/channels/issues/1399
    """
    def __init__(self, scope, middleware):
        self.middleware = middleware
        self.scope = dict(scope)
        self.inner = self.middleware.inner

    async def __call__(self, receive, send):
        headers = dict(self.scope['headers'])
        if b'authorization' in headers:
            self.scope['user'] = await get_user(headers)
        inner = self.inner(self.scope)
        return await inner(receive, send)


TokenAuthMiddlewareStack = lambda inner: TokenAuthMiddleware(AuthMiddlewareStack(inner))

像这样使用它:

代码语言:javascript
复制
# myproject/routing.py
from myapi.utils import TokenAuthMiddlewareStack
from myapi.websockets import WSAPIConsumer

application = ProtocolTypeRouter({
    "websocket": TokenAuthMiddlewareStack(
        URLRouter([
            path("api/v1/ws", WSAPIConsumer),
        ]),
    ),

})
application = SentryAsgiMiddleware(application)
票数 17
EN

Stack Overflow用户

发布于 2020-11-20 20:05:05

因为@tapion stated,这个解决方案在channels 3.x之后就不再工作了

较新的解决方案可以稍作调整:

代码语言:javascript
复制
class TokenAuthMiddleware:
    def __init__(self, inner):
        self.inner = inner

    async def __call__(self, scope, receive, send):
        headers = dict(scope['headers'])
        if b'authorization' in headers:
            scope['user'] = await get_user(headers)
        return await self.inner(scope, receive, send)
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60009296

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档