implement some auth for MeshUIConsumer
This commit is contained in:
parent
88d6f07eaf
commit
394450f4a3
4 changed files with 30 additions and 9 deletions
|
@ -3,8 +3,10 @@ from contextlib import suppress
|
||||||
|
|
||||||
from channels.auth import AuthMiddlewareStack
|
from channels.auth import AuthMiddlewareStack
|
||||||
from channels.routing import ProtocolTypeRouter, URLRouter
|
from channels.routing import ProtocolTypeRouter, URLRouter
|
||||||
|
from channels.security.websocket import AllowedHostsOriginValidator
|
||||||
from django.core.asgi import get_asgi_application
|
from django.core.asgi import get_asgi_application
|
||||||
|
|
||||||
|
from c3nav.control.middleware import UserPermissionsChannelMiddleware
|
||||||
from c3nav.urls import websocket_urlpatterns
|
from c3nav.urls import websocket_urlpatterns
|
||||||
|
|
||||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "c3nav.settings")
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "c3nav.settings")
|
||||||
|
@ -12,8 +14,12 @@ django_asgi = get_asgi_application()
|
||||||
|
|
||||||
application = ProtocolTypeRouter({
|
application = ProtocolTypeRouter({
|
||||||
"http": django_asgi,
|
"http": django_asgi,
|
||||||
"websocket": AuthMiddlewareStack(
|
"websocket": AllowedHostsOriginValidator(
|
||||||
URLRouter(websocket_urlpatterns)
|
AuthMiddlewareStack(
|
||||||
|
UserPermissionsChannelMiddleware(
|
||||||
|
URLRouter(websocket_urlpatterns),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -30,7 +36,4 @@ with suppress(ImportError):
|
||||||
Mount(settings.STATIC_URL, app=StaticFiles(directory=settings.STATIC_ROOT), name='static'),
|
Mount(settings.STATIC_URL, app=StaticFiles(directory=settings.STATIC_ROOT), name='static'),
|
||||||
Mount('/', app=django_asgi),
|
Mount('/', app=django_asgi),
|
||||||
]),
|
]),
|
||||||
"websocket": AuthMiddlewareStack(
|
|
||||||
URLRouter(websocket_urlpatterns)
|
|
||||||
),
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,8 +1,15 @@
|
||||||
from django.utils.functional import SimpleLazyObject, lazy
|
from channels.db import database_sync_to_async
|
||||||
|
from channels.middleware import BaseMiddleware as BaseChannelsMiddleware
|
||||||
|
from django.utils.functional import LazyObject, SimpleLazyObject, lazy
|
||||||
|
|
||||||
from c3nav.control.models import UserPermissions, UserSpaceAccess
|
from c3nav.control.models import UserPermissions, UserSpaceAccess
|
||||||
|
|
||||||
|
|
||||||
|
class UserPermissionsLazyObject(LazyObject):
|
||||||
|
def _setup(self):
|
||||||
|
raise ValueError("Accessing scope user before it is ready.")
|
||||||
|
|
||||||
|
|
||||||
class UserPermissionsMiddleware:
|
class UserPermissionsMiddleware:
|
||||||
"""
|
"""
|
||||||
This middleware adds request.user_permissions to get the UserPermissions for the current request/user.
|
This middleware adds request.user_permissions to get the UserPermissions for the current request/user.
|
||||||
|
@ -32,3 +39,12 @@ class UserPermissionsMiddleware:
|
||||||
request.user_permissions = SimpleLazyObject(lambda: self.get_user_permissions(request))
|
request.user_permissions = SimpleLazyObject(lambda: self.get_user_permissions(request))
|
||||||
request.user_space_accesses = lazy(self.get_user_space_accesses, dict)(request)
|
request.user_space_accesses = lazy(self.get_user_space_accesses, dict)(request)
|
||||||
return self.get_response(request)
|
return self.get_response(request)
|
||||||
|
|
||||||
|
|
||||||
|
class UserPermissionsChannelMiddleware(BaseChannelsMiddleware):
|
||||||
|
async def __call__(self, scope, receive, send):
|
||||||
|
# todo: this doesn't seem to actually be lazy. and scope["user"] isn't either?
|
||||||
|
scope["user_permissions"] = UserPermissionsLazyObject()
|
||||||
|
scope["user_permissions"]._wrapped = await database_sync_to_async(UserPermissions.get_for_user)(scope["user"])
|
||||||
|
|
||||||
|
return await super().__call__(scope, receive, send)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from typing import Dict
|
from typing import Dict, Self
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
@ -73,7 +73,7 @@ class UserPermissions(models.Model):
|
||||||
yield
|
yield
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_for_user(cls, user, force=False) -> 'UserPermissions':
|
def get_for_user(cls, user, force=False) -> Self:
|
||||||
if not user.is_authenticated:
|
if not user.is_authenticated:
|
||||||
return cls()
|
return cls()
|
||||||
cache_key = cls.get_cache_key(user.pk)
|
cache_key = cls.get_cache_key(user.pk)
|
||||||
|
|
|
@ -5,6 +5,7 @@ from functools import cached_property
|
||||||
|
|
||||||
from asgiref.sync import async_to_sync
|
from asgiref.sync import async_to_sync
|
||||||
from channels.db import database_sync_to_async
|
from channels.db import database_sync_to_async
|
||||||
|
from channels.exceptions import DenyConnection
|
||||||
from channels.generic.websocket import AsyncJsonWebsocketConsumer, AsyncWebsocketConsumer
|
from channels.generic.websocket import AsyncJsonWebsocketConsumer, AsyncWebsocketConsumer
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
@ -347,7 +348,8 @@ class MeshUIConsumer(AsyncJsonWebsocketConsumer):
|
||||||
self.msg_received_filter = {}
|
self.msg_received_filter = {}
|
||||||
|
|
||||||
async def connect(self):
|
async def connect(self):
|
||||||
# todo: auth
|
if not self.scope["user_permisions"].mesh_control:
|
||||||
|
raise DenyConnection
|
||||||
await self.accept()
|
await self.accept()
|
||||||
|
|
||||||
async def receive_json(self, content, **kwargs):
|
async def receive_json(self, content, **kwargs):
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue