首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Django通道自定义权限系统

Django通道自定义权限系统
EN

Stack Overflow用户
提问于 2021-01-26 12:32:57
回答 1查看 587关注 0票数 1

因此,我有一个系统,用户可以通过模型成员成为模型的一部分,称为boxes。

成员模型有自己的角色集,而这些角色又有自己的权限。

我有一些特定的方法来确定成员在框中拥有的权限集。

现在我有了一个名为'box_{box_id}‘的websocket组,成员可以连接到这个组。出站事件(如与框相关的模型创建)被发送到此组。

但是,一些成员不应该听取基于它们拥有的权限发送的某些事件。

这是一个发送给组的示例消息,该消息表示事件{' event ':EVENT TYPE,'data':EVENT }

因此,例如,如果用户在框中没有READ_UPLOADS权限,则无法侦听带有READ_UPLOADS类型的事件。

如何使用django通道实现这样的检查?

编辑

代码语言:javascript
复制
class LocalEventsConsumer(AsyncWebsocketConsumer):
    """
    An ASGI consumer for box-specific (local) event sending.
    Any valid member for the given box can connect to this consumer.
    """
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.box_id = self.scope['url_route']['kwargs']['box_id']
        self.events_group_name = 'box_%s_events' % self.box_id

        self.overwrites_cache = {}
        self.permissions_cache = set()
        # need to update cache on role and overwrite updates

    async def connect(self):
        try:
            # we cache the member object on connection
            # to help check permissions later on during
            # firing of events
            member_kwargs = {
                'user': self.scope['user'],
                'box__id': self.box_id,
            }
            self.member = api_models.Member.objects.get(**member_kwargs)
            self.permissions_cache = self.member.base_permissions
        except ObjectDoesNotExist:
            # we reject the connection if the
            # box-id passed in the url was invalid
            # or the user isn't a member of the box yet
            await self.close()

        await self.channel_layer.group_add(self.events_group_name, self.channel_name)
        await self.accept()

    async def disconnect(self, close_code):
        await self.channel_layer.group_discard(self.events_group_name, self.channel_name)

    async def fire_event(self, event: dict):
        member_permissions = self.get_event_permissions(event)
        required_permissions = event.pop('listener_permissions', set())
        if required_permissions in member_permissions:
            await self.send(event)

    def get_event_permissions(self, event):
        # handle permission caching throughout
        # the life of the user's connection
        overwrite_channel = event['data'].get('channel', None)
        overwrite_cache = self.overwrites_cache.get(overwrite_channel.id, None)
        if not overwrite_channel:
            # calculate overwrites if the event data at hand
            # has a channel attribute. We would need to calculate
            # overwrites only when channel-specific events are
            # triggered, like UPLOAD_CREATE and OVERWRITE_DELETE
            return self.permissions_cache
        if not overwrite_cache:
            overwrite_cache = self.member.permissions.get_overwrites(overwrite_channel)
            self.overwrites_cache[overwrite_channel.id] = overwrite_cache
        return overwrite_cache

    @receiver(post_delete, sender=api_models.MemberRole)
    @receiver(post_save, sender=api_models.MemberRole)
    def update_permissions_cache(self, instance=None, **kwargs):
        if instance.member == self.member:
            self.permissions_cache = self.member.base_permissions

    @receiver(post_delete, sender=api_models.Overwrite)
    @receiver(post_save, sender=api_models.Overwrite)
    def update_overwrites_cache(self, instance=None, **kwargs):
        overwrite_cache = self.overwrites_cache.get(instance.channel, None)
        if instance.role in self.member.roles.all() and overwrite_cache:
            self.overwrites_cache[instance.channel] = self.member.permissions.get_overwrites(instance.channel)

这是我现在的消费者。我在使用者之外使用fire_event类型。但是,每次我需要获得权限时,我都需要访问数据库。因此,我已经实现了这个权限缓存系统来减轻这种情况。同样的应该改变吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-01-26 15:09:59

可以在向客户端发送数据的方法中检查这些权限。因为它们都属于同一个信道组,所以您不能过滤到发送到组的级别,至少据我所知。所以你可以做这样的事情:

代码语言:javascript
复制
def receive(self, event):
    # update box
    ...
    # notify the members
    self.channel_layer.group_send(
        f'box_{self.box.id}', 
        {'type': 'notify_box_update', 'event': EVENT TYPE, 'data': EVENT DATA},
    )

def notify_box_update(event):
    if has_permission(self.user, event['event'], self.box):
        self.send(event)

在这里,通知事件是通过channel_layer发送给组的,但是只有具有适当权限的用户才会将其发送到下游。您可以在代码中的某个地方实现has_permission方法,以检查给定用户、框和事件类型的权限。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65901449

复制
相关文章

相似问题

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