channels 使用 djangorestframework-simplejwt 的token 验证用户有效性

文章目录

  • 前言
  • 一、安装好channels库后,在asgi设置好websocket路由
  • 二、使用步骤
    • 1.新建 channelsmiddleware.py 文件
    • 1.往 channelsmiddleware.py 添加
  • 总结


前言

channels 使用 djangorestframework-simplejwt 的token 验证用户有效性


一、安装好channels库后,在asgi设置好websocket路由

官方推荐的写法

# mysite/asgi.py
import os

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
import chat.routing

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")

application = ProtocolTypeRouter({
  "http": get_asgi_application(),
  "websocket": AuthMiddlewareStack(
        URLRouter(
            chat.routing.websocket_urlpatterns
        )
    ),
})

但是 AuthMiddlewareStack 并不能帮我们解析到用户实例,包括我们要自定义的方法,很不方便,而且我用的 djangorestframework-simplejwt 库来校验用户,于是我重新了一个方法

二、使用步骤

1.新建 channelsmiddleware.py 文件

修改asgi:

# mysite/asgi.py
import os

from mysite.channelsmiddleware import JwtAuthMiddleware
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
import chat.routing

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")

application = ProtocolTypeRouter({
  "http": get_asgi_application(),
  "websocket": JwtAuthMiddleware(
        URLRouter(
            chat.routing.websocket_urlpatterns
        )
    ),
})

1.往 channelsmiddleware.py 添加

# mysite/channelsmiddleware.py


from channels.auth import AuthMiddlewareStack
from channels.db import database_sync_to_async
from channels.middleware import BaseMiddleware
from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.auth.models import AnonymousUser, User
from django.db import close_old_connections
from jwt import decode as jwt_decode
from rest_framework_simplejwt.authentication import AUTH_HEADER_TYPE_BYTES
from rest_framework_simplejwt.exceptions import InvalidToken, TokenError
from rest_framework_simplejwt.tokens import UntypedToken


@database_sync_to_async
def get_user(validated_token):
    try:
        user = get_user_model().objects.get(id=validated_token["user_id"])
        # return get_user_model().objects.get(id=toke_id)
        return user

    except User.DoesNotExist:
        return AnonymousUser()


class JwtAuthMiddleware(BaseMiddleware):
    def __init__(self, inner):
        self.inner = inner

    async def __call__(self, scope, receive, send):
        # Close old database connections to prevent usage of timed out connections
        close_old_connections()
        parts = dict(scope['headers']).get(b'authorization', b'').split()
        if len(parts) == 0:
            # Empty AUTHORIZATION header sent
            return None

        if parts[0] not in AUTH_HEADER_TYPE_BYTES:
            # Assume the header does not contain a JSON web token
            return None

        if len(parts) != 2:
            raise None

        token = parts[1]
        # Get the token
        # Try to authenticate the user
        try:
            # This will automatically validate the token and raise an error if token is invalid
            UntypedToken(token)
        except (InvalidToken, TokenError) as e:
            # Token is invalid
            print(e)
            return None
        else:
            #  Then token is valid, decode it
            decoded_data = jwt_decode(token, settings.SECRET_KEY, algorithms=["HS256"])
            print(decoded_data)
            # Will return a dictionary like -
            # {
            #     "token_type": "access",
            #     "exp": 1568770772,
            #     "jti": "5c15e80d65b04c20ad34d77b6703251b",
            #     "user_id": 6
            # }

            # Get the user using ID
            scope["user"] = await get_user(validated_token=decoded_data)
        return await super().__call__(scope, receive, send)


def JwtAuthMiddlewareStack(inner):
    return JwtAuthMiddleware(AuthMiddlewareStack(inner))

现在就可以在channels里通过 self.scope[“user”] 获取到一个用户实例了。

总结

以上就是我的方法,多看看源代码,找找资料,其实也不是很难。

你可能感兴趣的:(聊天室,django,python)