如何在Django频道上使用Knox令牌认证来认证Websocket连接?

时间:2019-06-19 15:29:50

标签: authentication websocket django-rest-framework django-channels django-rest-knox

我了解您可以编写自定义身份验证中间件以在Django通道2中使用。 这在Django的内置令牌身份验证中可以很好地工作,但是使用django-rest-knox令牌是另一回事。 Knox以加密形式存储其令牌,因此它不像通过查找令牌从数据库中检索用户那样简单。 请帮忙。

2 个答案:

答案 0 :(得分:0)

想通了!

from knox.auth import TokenAuthentication
...
knoxAuth = TokenAuthentication();
user, auth_token = knoxAuth.authenticate_credentials(tokenString.encode(HTTP_HEADER_ENCODING))
scope['user'] = user

将以上代码与https://gist.github.com/rluts/22e05ed8f53f97bdd02eafdf38f3d60a

集成

答案 1 :(得分:0)

为了能够使用令牌身份验证来对用户进行身份验证,必须使用cookie。可以使用WS发送的标头是有限的,还必须实现自己的“ TokenAuthMiddleware”来处理cookie。对于通道2,您还必须正确处理对数据库的访问,以下是操作方法:

from    channels.auth                   import  AuthMiddlewareStack
from    channels.db                     import  database_sync_to_async
from    knox.auth                       import  TokenAuthentication
from    django.contrib.auth.models      import  AnonymousUser
from    django.db                       import  close_old_connections
from    rest_framework.exceptions       import  AuthenticationFailed

import  re

class TokenAuthMiddlewareInstance   :
    def __init__            (
        #
                self        ,
                scope       ,
                middleware  ,
            ):
        self.middleware = middleware
        self.scope      = dict(scope)
        self.inner      = self.middleware.inner
    async def __call__      (
        #
                self    ,
                receive ,
                send    ,
            ):
        self.scope['user']  = AnonymousUser()
        cookie              = dict(self.scope.get('headers',{})).get(b'cookie')

        if      cookie  :
            token   = re.findall(r'X-Authorization=(\w*)', cookie.decode('ascii'))
            if      len(token)  :
                self.scope['user']   = await self._g_user(token)

        inner = self.inner(self.scope)
        return await inner(receive, send)
    
    @database_sync_to_async
    def _g_user (
        #
                self    ,
                token   ,
            ):
        try                                 :
            token_key       = token[0]
            user, token     = TokenAuthentication().authenticate_credentials(token_key.encode('ascii'))
            close_old_connections()
            return user
        except AuthenticationFailed as e    :
            return AnonymousUser()
class TokenAuthMiddleware           :
    def __init__    (
        #
                self    ,
                inner   ,
            ):
        self.inner = inner

    def __call__    (
        #
                self    ,
                scope   ,
            ):
        return TokenAuthMiddlewareInstance(scope, self)
TokenAuthMiddlewareStack            = lambda inner: TokenAuthMiddleware(AuthMiddlewareStack(inner))