mirror of https://github.com/jumpserver/jumpserver
perf: 优化授权规则获取用户授权的账号API
parent
aa9e5d2432
commit
e118ed655b
|
@ -19,7 +19,6 @@ __all__ = [
|
|||
'UserGroupGrantedAssetsApi', 'UserGroupGrantedNodesApi',
|
||||
'UserGroupGrantedNodeAssetsApi',
|
||||
'UserGroupGrantedNodeChildrenAsTreeApi',
|
||||
'UserGroupGrantedAssetAccountsApi',
|
||||
]
|
||||
|
||||
|
||||
|
@ -191,17 +190,3 @@ class UserGroupGrantedNodeChildrenAsTreeApi(SerializeToTreeNodeMixin, ListAPIVie
|
|||
nodes = self.get_nodes()
|
||||
nodes = self.serialize_nodes(nodes)
|
||||
return Response(data=nodes)
|
||||
|
||||
|
||||
class UserGroupGrantedAssetAccountsApi(uapi.UserGrantedAssetAccountsApi):
|
||||
|
||||
@lazyproperty
|
||||
def user_group(self):
|
||||
group_id = self.kwargs.get('pk')
|
||||
return UserGroup.objects.get(id=group_id)
|
||||
|
||||
def get_queryset(self):
|
||||
accounts = PermAccountUtil().get_perm_accounts_for_user_group_asset(
|
||||
self.user_group, self.asset, with_actions=True
|
||||
)
|
||||
return accounts
|
||||
|
|
|
@ -10,12 +10,12 @@ from .mixin import SelfOrPKUserMixin
|
|||
logger = get_logger(__name__)
|
||||
|
||||
__all__ = [
|
||||
'UserGrantedAssetAccountsApi',
|
||||
'UserPermedAssetAccountsApi',
|
||||
]
|
||||
|
||||
|
||||
class UserGrantedAssetAccountsApi(SelfOrPKUserMixin, ListAPIView):
|
||||
serializer_class = serializers.AccountsGrantedSerializer
|
||||
class UserPermedAssetAccountsApi(SelfOrPKUserMixin, ListAPIView):
|
||||
serializer_class = serializers.AccountsPermedSerializer
|
||||
|
||||
@lazyproperty
|
||||
def asset(self):
|
||||
|
|
|
@ -6,7 +6,7 @@ from django.utils.translation import ugettext_lazy as _
|
|||
from common.db.fields import BitChoices
|
||||
from common.utils.integer import bit
|
||||
|
||||
__all__ = ["SpecialAccount", "ActionChoices"]
|
||||
__all__ = ["ActionChoices"]
|
||||
|
||||
|
||||
class ActionChoices(BitChoices):
|
||||
|
@ -31,7 +31,3 @@ class ActionChoices(BitChoices):
|
|||
def has_perm(cls, action_name, total):
|
||||
action_value = getattr(cls, action_name)
|
||||
return action_value & total == action_value
|
||||
|
||||
|
||||
class SpecialAccount(models.TextChoices):
|
||||
ALL = "@ALL", "All"
|
||||
|
|
|
@ -11,7 +11,7 @@ from common.db.models import UnionQuerySet
|
|||
from common.utils import date_expired_default
|
||||
from orgs.mixins.models import OrgManager
|
||||
from orgs.mixins.models import OrgModelMixin
|
||||
from perms.const import ActionChoices, SpecialAccount
|
||||
from perms.const import ActionChoices
|
||||
|
||||
__all__ = ['AssetPermission', 'ActionChoices']
|
||||
|
||||
|
@ -37,7 +37,7 @@ class AssetPermissionQuerySet(models.QuerySet):
|
|||
|
||||
def filter_by_accounts(self, accounts):
|
||||
q = Q(accounts__contains=list(accounts)) | \
|
||||
Q(accounts__contains=SpecialAccount.ALL.value)
|
||||
Q(accounts__contains=Account.AliasAccount.ALL.value)
|
||||
return self.filter(q)
|
||||
|
||||
|
||||
|
@ -127,7 +127,7 @@ class AssetPermission(OrgModelMixin):
|
|||
"""
|
||||
asset_ids = self.get_all_assets(flat=True)
|
||||
q = Q(asset_id__in=asset_ids)
|
||||
if SpecialAccount.ALL in self.accounts:
|
||||
if Account.AliasAccount.ALL in self.accounts:
|
||||
q &= Q(username__in=self.accounts)
|
||||
accounts = Account.objects.filter(q).order_by('asset__name', 'name', 'username')
|
||||
if not flat:
|
||||
|
|
|
@ -11,7 +11,7 @@ from perms.serializers.permission import ActionChoicesField
|
|||
|
||||
__all__ = [
|
||||
'NodeGrantedSerializer', 'AssetGrantedSerializer',
|
||||
'ActionsSerializer', 'AccountsGrantedSerializer'
|
||||
'ActionsSerializer', 'AccountsPermedSerializer'
|
||||
]
|
||||
|
||||
|
||||
|
@ -48,7 +48,7 @@ class ActionsSerializer(serializers.Serializer):
|
|||
actions = ActionChoicesField(read_only=True)
|
||||
|
||||
|
||||
class AccountsGrantedSerializer(serializers.ModelSerializer):
|
||||
class AccountsPermedSerializer(serializers.ModelSerializer):
|
||||
actions = ActionChoicesField(read_only=True)
|
||||
|
||||
class Meta:
|
||||
|
|
|
@ -55,8 +55,9 @@ user_permission_urlpatterns = [
|
|||
name='my-ungrouped-assets'),
|
||||
|
||||
# 获取授权给用户某个资产的所有账号
|
||||
path('<str:user>/assets/<uuid:asset_id>/accounts/', api.UserGrantedAssetAccountsApi.as_view(),
|
||||
name='user-asset-accounts'),
|
||||
# user params: ['my', 'self'] or user.id
|
||||
path('<str:user>/assets/<uuid:asset_id>/accounts/', api.UserPermedAssetAccountsApi.as_view(),
|
||||
name='user-permed-asset-accounts'),
|
||||
]
|
||||
|
||||
user_group_permission_urlpatterns = [
|
||||
|
@ -68,10 +69,6 @@ user_group_permission_urlpatterns = [
|
|||
name='user-group-nodes-children-as-tree'),
|
||||
path('<uuid:pk>/nodes/<uuid:node_id>/assets/', api.UserGroupGrantedNodeAssetsApi.as_view(),
|
||||
name='user-group-node-assets'),
|
||||
|
||||
# 获取所有和资产-用户组关联的账号列表
|
||||
path('<uuid:pk>/assets/<uuid:asset_id>/accounts/', api.UserGroupGrantedAssetAccountsApi.as_view(),
|
||||
name='user-group-asset-accounts'),
|
||||
]
|
||||
|
||||
user_permission_urlpatterns = [
|
||||
|
|
|
@ -9,6 +9,19 @@ __all__ = ['PermAccountUtil']
|
|||
class PermAccountUtil(AssetPermissionUtil):
|
||||
""" 资产授权账号相关的工具 """
|
||||
|
||||
def validate_permission(self, user, asset, account_username):
|
||||
""" 校验用户有某个资产下某个账号名的权限
|
||||
:param user: User
|
||||
:param asset: Asset
|
||||
:param account_username: 可能是 @USER @INPUT 字符串
|
||||
"""
|
||||
permed_accounts = self.get_permed_accounts_for_user(user, asset)
|
||||
accounts_mapper = {account.username: account for account in permed_accounts}
|
||||
|
||||
account = accounts_mapper.get(account_username)
|
||||
actions, date_expired = (account.actions, account.date_expired) if account else (False, None)
|
||||
return actions, date_expired
|
||||
|
||||
def get_permed_accounts_for_user(self, user, asset):
|
||||
""" 获取授权给用户某个资产的账号 """
|
||||
perms = self.get_permissions_for_user_asset(user, asset)
|
||||
|
@ -17,6 +30,7 @@ class PermAccountUtil(AssetPermissionUtil):
|
|||
|
||||
@staticmethod
|
||||
def get_permed_accounts_from_perms(perms, user, asset):
|
||||
# alias: is a collection of account usernames and special accounts [@ALL, @INPUT, @USER]
|
||||
alias_action_bit_mapper = defaultdict(int)
|
||||
alias_expired_mapper = defaultdict(list)
|
||||
|
||||
|
@ -27,23 +41,26 @@ class PermAccountUtil(AssetPermissionUtil):
|
|||
|
||||
asset_accounts = asset.accounts.all()
|
||||
username_account_mapper = {account.username: account for account in asset_accounts}
|
||||
|
||||
cleaned_accounts_action_bit = defaultdict(int)
|
||||
cleaned_accounts_expired = defaultdict(list)
|
||||
|
||||
# @ALL 账号先处理,后面的每个最多映射一个账号
|
||||
all_action_bit = alias_action_bit_mapper.pop('@ALL', None)
|
||||
all_action_bit = alias_action_bit_mapper.pop(Account.AliasAccount.ALL, None)
|
||||
if all_action_bit:
|
||||
for account in asset_accounts:
|
||||
cleaned_accounts_action_bit[account] |= all_action_bit
|
||||
cleaned_accounts_expired[account].extend(alias_expired_mapper['@ALL'])
|
||||
cleaned_accounts_expired[account].extend(
|
||||
alias_expired_mapper[Account.AliasAccount.ALL]
|
||||
)
|
||||
|
||||
for alias, action_bit in alias_action_bit_mapper.items():
|
||||
if alias == '@USER':
|
||||
if alias == Account.AliasAccount.USER:
|
||||
if user.username in username_account_mapper:
|
||||
account = username_account_mapper[user.username]
|
||||
else:
|
||||
account = Account.get_user_account(user.username)
|
||||
elif alias == '@INPUT':
|
||||
elif alias == Account.AliasAccount.INPUT:
|
||||
account = Account.get_manual_account()
|
||||
elif alias in username_account_mapper:
|
||||
account = username_account_mapper[alias]
|
||||
|
@ -60,29 +77,3 @@ class PermAccountUtil(AssetPermissionUtil):
|
|||
account.date_expired = max(cleaned_accounts_expired[account])
|
||||
accounts.append(account)
|
||||
return accounts
|
||||
|
||||
@staticmethod
|
||||
def get_accounts_for_permission(perm, with_actions=False):
|
||||
""" 获取授权规则包含的账号 """
|
||||
aid_actions_map = defaultdict(int)
|
||||
# 这里不行,速度太慢, 别情有很多查询
|
||||
account_ids = perm.get_all_accounts(flat=True)
|
||||
actions = perm.actions
|
||||
for aid in account_ids:
|
||||
aid_actions_map[str(aid)] |= actions
|
||||
account_ids = list(aid_actions_map.keys())
|
||||
accounts = Account.objects.filter(id__in=account_ids)
|
||||
return accounts
|
||||
|
||||
def validate_permission(self, user, asset, account_username):
|
||||
""" 校验用户有某个资产下某个账号名的权限
|
||||
:param account_username: 可能是 @USER @INPUT 的
|
||||
"""
|
||||
permed_accounts = self.get_permed_accounts_for_user(user, asset)
|
||||
accounts_mapper = {account.username: account for account in permed_accounts}
|
||||
|
||||
account = accounts_mapper.get(account_username)
|
||||
if not account:
|
||||
return False, None
|
||||
else:
|
||||
return account.actions, account.date_expired
|
||||
|
|
Loading…
Reference in New Issue