mirror of https://github.com/jumpserver/jumpserver
fix(perms): 用户添加到用户组报错
parent
b8ff3b38bf
commit
6701a1b604
|
@ -1,12 +1,14 @@
|
|||
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist as DJObjectDoesNotExist
|
||||
from django.http import Http404
|
||||
from django.utils.translation import gettext
|
||||
|
||||
from rest_framework import exceptions
|
||||
from rest_framework.views import set_rollback
|
||||
from rest_framework.response import Response
|
||||
|
||||
from common.exceptions import JMSObjectDoesNotExist
|
||||
from common.utils import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def extract_object_name(exc, index=0):
|
||||
|
@ -20,6 +22,8 @@ def extract_object_name(exc, index=0):
|
|||
|
||||
|
||||
def common_exception_handler(exc, context):
|
||||
logger.exception('')
|
||||
|
||||
if isinstance(exc, Http404):
|
||||
exc = JMSObjectDoesNotExist(object_name=extract_object_name(exc, 1))
|
||||
elif isinstance(exc, PermissionDenied):
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
from django.http import HttpResponse
|
||||
from django.utils.encoding import iri_to_uri
|
||||
|
||||
from rest_framework.serializers import BooleanField
|
||||
|
||||
|
||||
class HttpResponseTemporaryRedirect(HttpResponse):
|
||||
status_code = 307
|
||||
|
@ -14,3 +16,7 @@ class HttpResponseTemporaryRedirect(HttpResponse):
|
|||
|
||||
def get_remote_addr(request):
|
||||
return request.META.get("HTTP_X_FORWARDED_HOST") or request.META.get("REMOTE_ADDR")
|
||||
|
||||
|
||||
def is_true(value):
|
||||
return value in BooleanField.TRUE_VALUES
|
||||
|
|
|
@ -17,7 +17,7 @@ from ...utils.user_asset_permission import (
|
|||
get_indirect_granted_node_children,
|
||||
get_user_granted_nodes_list_via_mapping_node,
|
||||
get_top_level_granted_nodes,
|
||||
init_user_tree_if_need,
|
||||
rebuild_user_tree_if_need,
|
||||
)
|
||||
|
||||
|
||||
|
@ -61,7 +61,7 @@ class BaseGrantedNodeApi(_GrantedNodeStructApi, metaclass=abc.ABCMeta):
|
|||
|
||||
@tmp_to_root_org()
|
||||
def list(self, request, *args, **kwargs):
|
||||
init_user_tree_if_need(self.user)
|
||||
rebuild_user_tree_if_need(request, self.user)
|
||||
nodes = self.get_nodes()
|
||||
serializer = self.get_serializer(nodes, many=True)
|
||||
return Response(serializer.data)
|
||||
|
@ -73,8 +73,8 @@ class BaseNodeChildrenApi(NodeChildrenMixin, BaseGrantedNodeApi, metaclass=abc.A
|
|||
|
||||
class BaseGrantedNodeAsTreeApi(SerializeToTreeNodeMixin, _GrantedNodeStructApi, metaclass=abc.ABCMeta):
|
||||
@tmp_to_root_org()
|
||||
def list(self, request, *args, **kwargs):
|
||||
init_user_tree_if_need(self.user)
|
||||
def list(self, request: Request, *args, **kwargs):
|
||||
rebuild_user_tree_if_need(request, self.user)
|
||||
nodes = self.get_nodes()
|
||||
nodes = self.serialize_nodes(nodes, with_asset_amount=True)
|
||||
return Response(data=nodes)
|
||||
|
|
|
@ -12,7 +12,7 @@ from ...utils.user_asset_permission import (
|
|||
get_indirect_granted_node_children, UNGROUPED_NODE_KEY, FAVORITE_NODE_KEY,
|
||||
get_user_direct_granted_assets, get_top_level_granted_nodes,
|
||||
get_user_granted_nodes_list_via_mapping_node,
|
||||
get_user_granted_all_assets, init_user_tree_if_need,
|
||||
get_user_granted_all_assets, rebuild_user_tree_if_need,
|
||||
get_user_all_assetpermission_ids,
|
||||
)
|
||||
|
||||
|
@ -38,7 +38,7 @@ class MyGrantedNodesWithAssetsAsTreeApi(SerializeToTreeNodeMixin, ListAPIView):
|
|||
"""
|
||||
|
||||
user = request.user
|
||||
init_user_tree_if_need(user)
|
||||
rebuild_user_tree_if_need(request, user)
|
||||
all_nodes = get_user_granted_nodes_list_via_mapping_node(user)
|
||||
all_assets = get_user_granted_all_assets(user)
|
||||
|
||||
|
@ -106,7 +106,7 @@ class UserGrantedNodeChildrenWithAssetsAsTreeForAdminApi(ForAdminMixin, UserNode
|
|||
key = self.id2key_if_have()
|
||||
|
||||
user = self.user
|
||||
init_user_tree_if_need(user)
|
||||
rebuild_user_tree_if_need(request, user)
|
||||
nodes, assets = self.get_data(key, user)
|
||||
|
||||
tree_nodes = self.serialize_nodes(nodes, with_asset_amount=True)
|
||||
|
|
|
@ -4,16 +4,16 @@ from itertools import chain
|
|||
|
||||
from django.db.models.signals import m2m_changed, pre_delete, pre_save
|
||||
from django.dispatch import receiver
|
||||
from django.db import transaction
|
||||
|
||||
from django.db.models import Q
|
||||
|
||||
from perms.tasks import dispatch_mapping_node_tasks
|
||||
from perms.tasks import create_rebuild_user_tree_task
|
||||
from users.models import User, UserGroup
|
||||
from assets.models import Asset
|
||||
from common.utils import get_logger
|
||||
from common.utils import get_logger, get_object_or_none
|
||||
from common.exceptions import M2MReverseNotAllowed
|
||||
from common.const.signals import POST_ADD, POST_REMOVE, POST_CLEAR
|
||||
from .models import AssetPermission, RemoteAppPermission, RebuildUserTreeTask
|
||||
from .models import AssetPermission, RemoteAppPermission
|
||||
|
||||
|
||||
logger = get_logger(__file__)
|
||||
|
@ -21,9 +21,12 @@ logger = get_logger(__file__)
|
|||
|
||||
@receiver([pre_save], sender=AssetPermission)
|
||||
def on_asset_perm_deactive(instance: AssetPermission, **kwargs):
|
||||
try:
|
||||
old = AssetPermission.objects.only('is_active').get(id=instance.id)
|
||||
if instance.is_active != old.is_active:
|
||||
create_rebuild_user_tree_task_by_asset_perm(instance)
|
||||
except AssetPermission.DoesNotExist:
|
||||
pass
|
||||
|
||||
|
||||
@receiver([pre_delete], sender=AssetPermission)
|
||||
|
@ -32,13 +35,6 @@ def on_asset_permission_delete(instance, **kwargs):
|
|||
create_rebuild_user_tree_task_by_asset_perm(instance)
|
||||
|
||||
|
||||
def create_rebuild_user_tree_task(user_ids):
|
||||
RebuildUserTreeTask.objects.bulk_create(
|
||||
[RebuildUserTreeTask(user_id=i) for i in user_ids]
|
||||
)
|
||||
transaction.on_commit(dispatch_mapping_node_tasks.delay)
|
||||
|
||||
|
||||
def create_rebuild_user_tree_task_by_asset_perm(asset_perm: AssetPermission):
|
||||
user_ids = set()
|
||||
user_ids.update(
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
from __future__ import absolute_import, unicode_literals
|
||||
from datetime import timedelta
|
||||
|
||||
from django.db import transaction
|
||||
from django.db.models import Q
|
||||
from django.conf import settings
|
||||
from celery import shared_task
|
||||
|
@ -9,23 +10,25 @@ from common.utils import get_logger
|
|||
from common.utils.timezone import now
|
||||
from users.models import User
|
||||
from perms.models import RebuildUserTreeTask, AssetPermission
|
||||
from perms.utils.user_asset_permission import rebuild_user_mapping_nodes_if_need_with_lock
|
||||
from perms.utils.user_asset_permission import rebuild_user_mapping_nodes_if_need_with_lock, lock
|
||||
|
||||
logger = get_logger(__file__)
|
||||
|
||||
|
||||
@shared_task(queue='node_tree')
|
||||
def rebuild_user_mapping_nodes_celery_task(user_id):
|
||||
logger.info(f'>>> rebuild user[{user_id}] mapping nodes')
|
||||
user = User.objects.get(id=user_id)
|
||||
try:
|
||||
rebuild_user_mapping_nodes_if_need_with_lock(user)
|
||||
except lock.SomeoneIsDoingThis:
|
||||
pass
|
||||
|
||||
|
||||
@shared_task(queue='node_tree')
|
||||
def dispatch_mapping_node_tasks():
|
||||
user_ids = RebuildUserTreeTask.objects.all().values_list('user_id', flat=True).distinct()
|
||||
logger.info(f'>>> dispatch_mapping_node_tasks for users {list(user_ids)}')
|
||||
for id in user_ids:
|
||||
logger.info(f'>>> dispatch mapping node task for user[{id}]')
|
||||
rebuild_user_mapping_nodes_celery_task.delay(id)
|
||||
|
||||
|
||||
|
@ -55,3 +58,10 @@ def dispatch_process_expired_asset_permission(asset_perm_ids):
|
|||
)
|
||||
|
||||
dispatch_mapping_node_tasks.delay()
|
||||
|
||||
|
||||
def create_rebuild_user_tree_task(user_ids):
|
||||
RebuildUserTreeTask.objects.bulk_create(
|
||||
[RebuildUserTreeTask(user_id=i) for i in user_ids]
|
||||
)
|
||||
transaction.on_commit(dispatch_mapping_node_tasks.delay)
|
||||
|
|
|
@ -8,6 +8,7 @@ from django.conf import settings
|
|||
from django.db.models import F, Q, Value, BooleanField
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from common.http import is_true
|
||||
from common.utils import get_logger
|
||||
from common.const.distributed_lock_key import UPDATE_MAPPING_NODE_TASK_LOCK_KEY
|
||||
from orgs.utils import tmp_to_root_org
|
||||
|
@ -247,10 +248,12 @@ def set_node_granted_assets_amount(user, node):
|
|||
|
||||
|
||||
def rebuild_user_mapping_nodes(user):
|
||||
logger.info(f'>>> {dt_formater(now())} start rebuild {user} mapping nodes')
|
||||
tmp_nodes = compute_tmp_mapping_node_from_perm(user)
|
||||
for _node in tmp_nodes:
|
||||
set_node_granted_assets_amount(user, _node)
|
||||
create_mapping_nodes(user, tmp_nodes)
|
||||
logger.info(f'>>> {dt_formater(now())} end rebuild {user} mapping nodes')
|
||||
|
||||
|
||||
def get_user_granted_nodes_list_via_mapping_node(user):
|
||||
|
@ -486,12 +489,13 @@ def get_favorite_node(user):
|
|||
)
|
||||
|
||||
|
||||
def init_user_tree_if_need(user):
|
||||
def rebuild_user_tree_if_need(request, user):
|
||||
"""
|
||||
升级授权树策略后,用户的数据可能还未初始化,为防止用户显示没有数据
|
||||
先检查 MappingNode 如果没有数据,同步创建用户授权树
|
||||
"""
|
||||
if not UserGrantedMappingNode.objects.filter(user=user).exists():
|
||||
if is_true(request.query_params.get('rebuild_tree')) or \
|
||||
not UserGrantedMappingNode.objects.filter(user=user).exists():
|
||||
try:
|
||||
rebuild_user_mapping_nodes_with_lock(user)
|
||||
except lock.SomeoneIsDoingThis:
|
||||
|
|
|
@ -9,6 +9,7 @@ from django_cas_ng.signals import cas_user_authenticated
|
|||
|
||||
from jms_oidc_rp.signals import openid_create_or_update_user
|
||||
|
||||
from perms.tasks import create_rebuild_user_tree_task
|
||||
from common.utils import get_logger
|
||||
from .signals import post_user_create
|
||||
from .models import User
|
||||
|
@ -27,14 +28,12 @@ def on_user_create(sender, user=None, **kwargs):
|
|||
|
||||
|
||||
@receiver(m2m_changed, sender=User.groups.through)
|
||||
def on_user_groups_change(sender, instance=None, action='', **kwargs):
|
||||
"""
|
||||
资产节点发生变化时,刷新节点
|
||||
"""
|
||||
def on_user_groups_change(instance, action, reverse, pk_set, **kwargs):
|
||||
if action.startswith('post'):
|
||||
logger.debug("User group member change signal recv: {}".format(instance))
|
||||
from perms.utils import AssetPermissionUtil
|
||||
AssetPermissionUtil.expire_all_user_tree_cache()
|
||||
if reverse:
|
||||
create_rebuild_user_tree_task(pk_set)
|
||||
else:
|
||||
create_rebuild_user_tree_task([instance.id])
|
||||
|
||||
|
||||
@receiver(cas_user_authenticated)
|
||||
|
|
Loading…
Reference in New Issue