fix: 修复用户授权资产账号API及Model处理逻辑

pull/8931/head
Jiangjie.Bai 2022-09-28 18:40:33 +08:00
parent e3b138be3a
commit 351d3b297d
6 changed files with 98 additions and 73 deletions

View File

@ -1,4 +1,5 @@
from django.db import models
from django.db.models import Q
from django.utils.translation import gettext_lazy as _
from simple_history.models import HistoricalRecords
@ -54,6 +55,11 @@ class Account(BaseAccount):
""" @USER 动态用户的账号(self) """
return cls(name=cls.InnerAccount.USER.value, username=username)
@classmethod
def filter(cls, asset_ids, account_usernames):
queries = Q(asset_id__in=asset_ids) & Q(username__in=account_usernames)
return cls.objects.filter(queries)
class AccountTemplate(BaseAccount):
class Meta:

View File

@ -183,7 +183,8 @@ class Asset(AbsConnectivity, NodesRelationMixin, JMSOrgBaseModel):
return self.accounts.all()
if AssetPermission.SpecialAccount.ALL in account_names:
return self.accounts.all()
queries = Q(name__in=account_names) | Q(username__in=account_names)
# queries = Q(name__in=account_names) | Q(username__in=account_names)
queries = Q(username__in=account_names)
accounts = self.accounts.filter(queries)
return accounts

View File

@ -2,8 +2,8 @@
#
import uuid
import time
from collections import defaultdict
from django.db.models import Q
from django.shortcuts import get_object_or_404
from django.utils.decorators import method_decorator
from rest_framework.views import APIView, Response
@ -21,7 +21,7 @@ from common.utils import get_logger, lazyproperty
from perms.hands import User, Asset, Account
from perms import serializers
from perms.models import AssetPermission
from perms.models import AssetPermission, Action
logger = get_logger(__name__)
@ -162,15 +162,19 @@ class UserGrantedAssetAccounts(ListAPIView):
return asset
def get_queryset(self):
# 获取用户-资产的授权规则
assetperms = AssetPermission.filter(self.user, self.asset)
account_names = AssetPermission.get_account_names(assetperms)
accounts = list(self.asset.filter_accounts(account_names))
accounts = AssetPermission.get_user_perm_asset_accounts(
self.user, self.asset, with_actions=True
)
return accounts
# @INPUT @USER
inner_accounts = [Account.get_input_account(), Account.get_user_account(self.user.username)]
all_accounts = accounts + inner_accounts
# inner_accounts = [
# Account.get_input_account(), Account.get_user_account(self.user.username)
# ]
# for inner_account in inner_accounts:
# inner_account.actions = Action.ALL
# accounts = accounts + inner_accounts
# 构造默认包含的账号,如: @INPUT @USER
return all_accounts
# return accounts
class MyGrantedAssetAccounts(UserGrantedAssetAccounts):

View File

@ -5,6 +5,7 @@ from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from django.db import models
from django.db.models import F, Q, TextChoices
from collections import defaultdict
from assets.models import Asset, Node, FamilyMixin, Account
from orgs.mixins.models import OrgModelMixin
@ -76,6 +77,11 @@ class AssetPermissionQuerySet(models.QuerySet):
q = (Q(is_active=False) | Q(date_start__gt=now) | Q(date_expired__lt=now))
return self.filter(q)
def filter_by_accounts(self, accounts):
q = Q(accounts__contains=accounts) | \
Q(accounts__contains=AssetPermission.SpecialAccount.ALL.value)
return self.filter(q)
class AssetPermissionManager(OrgManager):
def valid(self):
@ -212,94 +218,96 @@ class AssetPermission(OrgModelMixin):
names = [node.full_value for node in self.nodes.all()]
return names
# Related accounts
def get_asset_accounts(self):
asset_ids = self.get_all_assets(flat=True)
queries = Q(asset_id__in=asset_ids) \
& (Q(username__in=self.accounts) | Q(name__in=self.accounts))
accounts = Account.objects.filter(queries)
accounts = Account.filter(asset_ids, self.accounts)
return accounts
@classmethod
def get_account_names(cls, perms):
def get_user_perm_asset_accounts(cls, user, asset: Asset, with_actions=False):
perms = cls.filter(user, asset)
all_account_names = cls.retrieve_account_names(perms)
accounts = asset.filter_accounts(all_account_names)
if with_actions:
cls.set_accounts_actions(accounts, perms=perms)
return accounts
@classmethod
def set_accounts_actions(cls, accounts, perms):
# set account actions
account_names = accounts.values_list('username', flat=True)
perms = perms.filter_by_accounts(account_names)
account_names_actions_map = defaultdict(set)
account_names_actions = perms.values_list('accounts', 'actions')
for account_names, actions in account_names_actions:
for account_name in account_names:
account_names_actions_map[account_name] |= actions
for account in accounts:
account.actions = account_names_actions_map.get(account.username)
return accounts
@classmethod
def retrieve_account_names(cls, perms):
account_names = set()
for perm in perms:
perm: cls
if not isinstance(perm.accounts, list):
continue
account_names.update(perm.accounts)
return account_names
@classmethod
def filter(cls, user=None, asset=None, account=None):
def filter(cls, user=None, asset=None, account_names=None):
""" 获取同时包含 用户-资产-账号 的授权规则 """
assetperm_ids = []
perm_ids = []
if user:
user_assetperm_ids = cls.filter_by_user(user, flat=True)
assetperm_ids.append(user_assetperm_ids)
perm_ids.append(user_assetperm_ids)
if asset:
asset_assetperm_ids = cls.filter_by_asset(asset, flat=True)
assetperm_ids.append(asset_assetperm_ids)
if account:
account_assetperm_ids = cls.filter_by_account(account, flat=True)
assetperm_ids.append(account_assetperm_ids)
perm_ids.append(asset_assetperm_ids)
# & 是同时满足,比如有用户,但是用户的规则是空,那么返回也应该是空
assetperm_ids = list(reduce(lambda x, y: set(x) & set(y), assetperm_ids))
assetperms = cls.objects.filter(id__in=assetperm_ids).valid().order_by('-date_expired')
return assetperms
perm_ids = list(reduce(lambda x, y: set(x) & set(y), perm_ids))
perms = cls.objects.filter(id__in=perm_ids)
if account_names:
perms = perms.filter_by_accounts(account_names)
return perms.valid().order_by('-date_expired')
@classmethod
def filter_by_user(cls, user, with_group=True, flat=False):
assetperm_ids = set()
user_assetperm_ids = AssetPermission.users.through.objects \
.filter(user_id=user.id) \
.values_list('assetpermission_id', flat=True) \
.distinct()
assetperm_ids.update(user_assetperm_ids)
perm_ids = set()
user_perm_ids = AssetPermission.users.through.objects.filter(
user_id=user.id
).values_list('assetpermission_id', flat=True).distinct()
perm_ids.update(user_perm_ids)
if with_group:
usergroup_ids = user.get_groups(flat=True)
usergroups_assetperm_id = AssetPermission.user_groups.through.objects \
.filter(usergroup_id__in=usergroup_ids) \
.values_list('assetpermission_id', flat=True) \
.distinct()
assetperm_ids.update(usergroups_assetperm_id)
usergroups_perm_id = AssetPermission.user_groups.through.objects.filter(
usergroup_id__in=usergroup_ids
).values_list('assetpermission_id', flat=True).distinct()
perm_ids.update(usergroups_perm_id)
if flat:
return assetperm_ids
else:
assetperms = cls.objects.filter(id__in=assetperm_ids).valid()
return assetperms
return perm_ids
perms = cls.objects.filter(id__in=perm_ids).valid()
return perms
@classmethod
def filter_by_asset(cls, asset, with_node=True, flat=False):
assetperm_ids = set()
asset_assetperm_ids = AssetPermission.assets.through.objects \
.filter(asset_id=asset.id) \
.values_list('assetpermission_id', flat=True)
assetperm_ids.update(asset_assetperm_ids)
perm_ids = set()
asset_perm_ids = AssetPermission.assets.through.objects.filter(
asset_id=asset.id
).values_list('assetpermission_id', flat=True).distinct()
perm_ids.update(asset_perm_ids)
if with_node:
node_ids = asset.get_all_nodes(flat=True)
node_assetperm_ids = AssetPermission.nodes.through.objects \
.filter(node_id__in=node_ids) \
.values_list('assetpermission_id', flat=True)
assetperm_ids.update(node_assetperm_ids)
node_perm_ids = AssetPermission.nodes.through.objects.filter(
node_id__in=node_ids
).values_list('assetpermission_id', flat=True).distinct()
perm_ids.update(node_perm_ids)
if flat:
return assetperm_ids
else:
assetperms = cls.objects.filter(id__in=assetperm_ids).valid()
return assetperms
@classmethod
def filter_by_account(cls, account, flat=False):
queries = Q(accounts__contains=account) | Q(accounts__contains=cls.SpecialAccount.ALL.value)
assetperms = cls.objects.filter(queries).valid()
if flat:
assetperm_ids = assetperms.values_list('id', flat=True)
return assetperm_ids
else:
return assetperms
return perm_ids
perms = cls.objects.filter(id__in=perm_ids).valid()
return perms
class UserAssetGrantedTreeNodeRelation(OrgModelMixin, FamilyMixin, BaseCreateUpdateModel):

View File

@ -49,8 +49,9 @@ class AccountsGrantedSerializer(serializers.ModelSerializer):
# Todo: 添加前端登录逻辑中需要的一些字段,比如:是否需要手动输入密码
# need_manual = serializers.BooleanField(label=_('Need manual input'))
actions = ActionsField(read_only=True)
class Meta:
model = Account
fields = ['id', 'name', 'username']
fields = ['id', 'name', 'username', 'actions']
read_only_fields = fields

View File

@ -58,14 +58,15 @@ user_permission_urlpatterns = [
# 收藏的资产
path('<uuid:pk>/nodes/favorite/assets/', api.UserFavoriteGrantedAssetsApi.as_view(), name='user-ungrouped-assets'),
path('nodes/favorite/assets/', api.MyFavoriteGrantedAssetsApi.as_view(), name='my-ungrouped-assets'),
# v3 中上面的 API 基本不用动
# Todo: 删除
# Todo: v3 删除
# Asset System users
path('<uuid:pk>/assets/<uuid:asset_id>/system-users/', api.UserGrantedAssetSystemUsersForAdminApi.as_view(), name='user-asset-system-users'),
path('assets/<uuid:asset_id>/system-users/', api.MyGrantedAssetSystemUsersApi.as_view(), name='my-asset-system-users'),
# Todo: 增加
# 获取所有和资产关联的账号列表
# Todo: v3 增加
# 获取所有和资产-用户关联的账号列表
path('<uuid:pk>/assets/<uuid:asset_id>/accounts/', api.UserGrantedAssetAccounts.as_view(), name='user-asset-accounts'),
path('assets/<uuid:asset_id>/accounts/', api.MyGrantedAssetAccounts.as_view(), name='my-asset-accounts')
]
@ -77,17 +78,21 @@ user_group_permission_urlpatterns = [
path('<uuid:pk>/nodes/children/', api.UserGroupGrantedNodesApi.as_view(), name='user-group-nodes-children'),
path('<uuid:pk>/nodes/children/tree/', api.UserGroupGrantedNodeChildrenAsTreeApi.as_view(), name='user-group-nodes-children-as-tree'),
path('<uuid:pk>/nodes/<uuid:node_id>/assets/', api.UserGroupGrantedNodeAssetsApi.as_view(), name='user-group-node-assets'),
# Todo: v3 删除
path('<uuid:pk>/assets/<uuid:asset_id>/system-users/', api.UserGroupGrantedAssetSystemUsersApi.as_view(), name='user-group-asset-system-users'),
# Todo: v3 增加
# 获取所有和资产-用户组关联的账号列表
path('<uuid:pk>/assets/<uuid:asset_id>/accounts/', api.UserGrantedAssetAccounts.as_view(), name='user-asset-accounts'),
]
permission_urlpatterns = [
# Todo: 获取规则中授权的所有账号列表
#
# 授权规则中授权的资产
path('<uuid:pk>/assets/all/', api.AssetPermissionAllAssetListApi.as_view(), name='asset-permission-all-assets'),
path('<uuid:pk>/users/all/', api.AssetPermissionAllUserListApi.as_view(), name='asset-permission-all-users'),
# 验证用户是否有某个资产和系统用户的权限
# Todo: API 需要修改,验证用户有某个账号的权限
path('user/validate/', api.ValidateUserAssetPermissionApi.as_view(), name='validate-user-asset-permission'),
path('user/actions/', api.GetUserAssetPermissionActionsApi.as_view(), name='get-user-asset-permission-actions'),