mirror of https://github.com/jumpserver/jumpserver
refactor: 添加授权相关的获取资产账号API、Model method
parent
a2c006f01b
commit
d23446016d
|
@ -5,8 +5,10 @@
|
||||||
import logging
|
import logging
|
||||||
import uuid
|
import uuid
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
from collections import Iterable
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db.models import Q
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from common.utils import lazyproperty
|
from common.utils import lazyproperty
|
||||||
|
@ -57,13 +59,17 @@ class NodesRelationMixin:
|
||||||
return nodes
|
return nodes
|
||||||
|
|
||||||
def get_all_nodes(self, flat=False):
|
def get_all_nodes(self, flat=False):
|
||||||
nodes = []
|
from ..node import Node
|
||||||
|
node_keys = set()
|
||||||
for node in self.get_nodes():
|
for node in self.get_nodes():
|
||||||
_nodes = node.get_ancestors(with_self=True)
|
ancestor_keys = node.get_ancestor_keys(with_self=True)
|
||||||
nodes.append(_nodes)
|
node_keys.update(ancestor_keys)
|
||||||
|
nodes = Node.objects.filter(key__in=node_keys).distinct()
|
||||||
if flat:
|
if flat:
|
||||||
nodes = list(reduce(lambda x, y: set(x) | set(y), nodes))
|
node_ids = set(nodes.values_list('id', flat=True))
|
||||||
return nodes
|
return node_ids
|
||||||
|
else:
|
||||||
|
return nodes
|
||||||
|
|
||||||
|
|
||||||
class Asset(AbsConnectivity, NodesRelationMixin, JMSOrgBaseModel):
|
class Asset(AbsConnectivity, NodesRelationMixin, JMSOrgBaseModel):
|
||||||
|
@ -161,6 +167,14 @@ class Asset(AbsConnectivity, NodesRelationMixin, JMSOrgBaseModel):
|
||||||
tree_node = TreeNode(**data)
|
tree_node = TreeNode(**data)
|
||||||
return tree_node
|
return tree_node
|
||||||
|
|
||||||
|
def filter_accounts(self, account_names=None):
|
||||||
|
if account_names is None:
|
||||||
|
return self.accounts.all()
|
||||||
|
assert isinstance(account_names, Iterable), '`account_names` must be an iterable object'
|
||||||
|
queries = Q(name__in=account_names) | Q(username__in=account_names)
|
||||||
|
accounts = self.accounts.filter(queries)
|
||||||
|
return accounts
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = [('org_id', 'name')]
|
unique_together = [('org_id', 'name')]
|
||||||
verbose_name = _("Asset")
|
verbose_name = _("Asset")
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import uuid
|
import uuid
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
from django.db.models import Q
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from rest_framework.views import APIView, Response
|
from rest_framework.views import APIView, Response
|
||||||
|
@ -20,6 +21,7 @@ from common.utils import get_logger, lazyproperty
|
||||||
|
|
||||||
from perms.hands import User, Asset
|
from perms.hands import User, Asset
|
||||||
from perms import serializers
|
from perms import serializers
|
||||||
|
from perms.models import AssetPermission
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
@ -28,6 +30,8 @@ __all__ = [
|
||||||
'ValidateUserAssetPermissionApi',
|
'ValidateUserAssetPermissionApi',
|
||||||
'GetUserAssetPermissionActionsApi',
|
'GetUserAssetPermissionActionsApi',
|
||||||
'MyGrantedAssetSystemUsersApi',
|
'MyGrantedAssetSystemUsersApi',
|
||||||
|
'UserGrantedAssetAccounts',
|
||||||
|
'MyGrantedAssetAccounts',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -138,3 +142,37 @@ class MyGrantedAssetSystemUsersApi(UserGrantedAssetSystemUsersForAdminApi):
|
||||||
def user(self):
|
def user(self):
|
||||||
return self.request.user
|
return self.request.user
|
||||||
|
|
||||||
|
|
||||||
|
class UserGrantedAssetAccounts(ListAPIView):
|
||||||
|
serializer_class = serializers.AccountsGrantedSerializer
|
||||||
|
rbac_perms = {
|
||||||
|
'list': 'perms.view_userassets'
|
||||||
|
}
|
||||||
|
|
||||||
|
@lazyproperty
|
||||||
|
def user(self):
|
||||||
|
user_id = self.kwargs.get('pk')
|
||||||
|
return User.objects.get(id=user_id)
|
||||||
|
|
||||||
|
@lazyproperty
|
||||||
|
def asset(self):
|
||||||
|
asset_id = self.kwargs.get('asset_id')
|
||||||
|
kwargs = {'id': asset_id, 'is_active': True}
|
||||||
|
asset = get_object_or_404(Asset, **kwargs)
|
||||||
|
return asset
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
# 获取用户-资产的授权规则
|
||||||
|
assetperms = AssetPermission.filter_permissions(self.user, self.asset)
|
||||||
|
account_names = AssetPermission.get_account_names(assetperms)
|
||||||
|
accounts = self.asset.filter_accounts(account_names)
|
||||||
|
# 构造默认包含的账号,如: @INPUT @USER
|
||||||
|
return accounts
|
||||||
|
|
||||||
|
|
||||||
|
class MyGrantedAssetAccounts(UserGrantedAssetAccounts):
|
||||||
|
permission_classes = (IsValidUser,)
|
||||||
|
|
||||||
|
@lazyproperty
|
||||||
|
def user(self):
|
||||||
|
return self.request.user
|
||||||
|
|
|
@ -19,7 +19,7 @@ from perms.utils.user_permission import UserGrantedNodesQueryUtils
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'UserGrantedNodesForAdminApi',
|
'UserGrantedNodesApi',
|
||||||
'MyGrantedNodesApi',
|
'MyGrantedNodesApi',
|
||||||
'MyGrantedNodesAsTreeApi',
|
'MyGrantedNodesAsTreeApi',
|
||||||
'UserGrantedNodeChildrenForAdminApi',
|
'UserGrantedNodeChildrenForAdminApi',
|
||||||
|
@ -118,11 +118,11 @@ class MyGrantedNodeChildrenAsTreeApi(AssetRoleUserMixin, UserGrantedNodeChildren
|
||||||
return permissions
|
return permissions
|
||||||
|
|
||||||
|
|
||||||
class UserGrantedNodesForAdminApi(AssetRoleAdminMixin, UserGrantedNodesMixin, BaseGrantedNodeApi):
|
class UserGrantedNodesApi(AssetRoleAdminMixin, UserGrantedNodesMixin, BaseGrantedNodeApi):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class MyGrantedNodesApi(AssetRoleUserMixin, UserGrantedNodesMixin, BaseGrantedNodeApi):
|
class MyGrantedNodesApi(AssetRoleUserMixin, UserGrantedNodesApi):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
import uuid
|
import uuid
|
||||||
import logging
|
import logging
|
||||||
|
from functools import reduce
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import F, Q, TextChoices
|
from django.db.models import F, Q, TextChoices
|
||||||
|
|
||||||
from assets.models import Asset, Node, FamilyMixin
|
from assets.models import Asset, Node, FamilyMixin, Account
|
||||||
from orgs.mixins.models import OrgModelMixin
|
from orgs.mixins.models import OrgModelMixin
|
||||||
from orgs.mixins.models import OrgManager
|
from orgs.mixins.models import OrgManager
|
||||||
from common.utils import lazyproperty, date_expired_default
|
from common.utils import lazyproperty, date_expired_default
|
||||||
from common.db.models import BaseCreateUpdateModel, BitOperationChoice, UnionQuerySet
|
from common.db.models import BaseCreateUpdateModel, BitOperationChoice, UnionQuerySet
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'AssetPermission', 'PermNode',
|
'AssetPermission', 'PermNode',
|
||||||
'UserAssetGrantedTreeNodeRelation',
|
'UserAssetGrantedTreeNodeRelation',
|
||||||
|
@ -85,20 +85,27 @@ class AssetPermissionManager(OrgManager):
|
||||||
class AssetPermission(OrgModelMixin):
|
class AssetPermission(OrgModelMixin):
|
||||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||||
name = models.CharField(max_length=128, verbose_name=_('Name'))
|
name = models.CharField(max_length=128, verbose_name=_('Name'))
|
||||||
users = models.ManyToManyField('users.User', blank=True, verbose_name=_("User"), related_name='%(class)ss')
|
users = models.ManyToManyField('users.User', blank=True, verbose_name=_("User"),
|
||||||
user_groups = models.ManyToManyField('users.UserGroup', blank=True, verbose_name=_("User group"), related_name='%(class)ss')
|
related_name='%(class)ss')
|
||||||
assets = models.ManyToManyField('assets.Asset', related_name='granted_by_permissions', blank=True, verbose_name=_("Asset"))
|
user_groups = models.ManyToManyField('users.UserGroup', blank=True,
|
||||||
nodes = models.ManyToManyField('assets.Node', related_name='granted_by_permissions', blank=True, verbose_name=_("Nodes"))
|
verbose_name=_("User group"), related_name='%(class)ss')
|
||||||
|
assets = models.ManyToManyField('assets.Asset', related_name='granted_by_permissions',
|
||||||
|
blank=True, verbose_name=_("Asset"))
|
||||||
|
nodes = models.ManyToManyField('assets.Node', related_name='granted_by_permissions', blank=True,
|
||||||
|
verbose_name=_("Nodes"))
|
||||||
# 只保存 @ALL (@INPUT @USER 默认包含,将来在全局设置中进行控制)
|
# 只保存 @ALL (@INPUT @USER 默认包含,将来在全局设置中进行控制)
|
||||||
# 特殊的账号描述
|
# 特殊的账号描述
|
||||||
# ['@ALL',]
|
# ['@ALL',]
|
||||||
# 指定账号授权
|
# 指定账号授权
|
||||||
# ['web', 'root',]
|
# ['web', 'root',]
|
||||||
accounts = models.JSONField(default=list, verbose_name=_("Accounts"))
|
accounts = models.JSONField(default=list, verbose_name=_("Accounts"))
|
||||||
actions = models.IntegerField(choices=Action.DB_CHOICES, default=Action.ALL, verbose_name=_("Actions"))
|
actions = models.IntegerField(choices=Action.DB_CHOICES, default=Action.ALL,
|
||||||
|
verbose_name=_("Actions"))
|
||||||
is_active = models.BooleanField(default=True, verbose_name=_('Active'))
|
is_active = models.BooleanField(default=True, verbose_name=_('Active'))
|
||||||
date_start = models.DateTimeField(default=timezone.now, db_index=True, verbose_name=_("Date start"))
|
date_start = models.DateTimeField(default=timezone.now, db_index=True,
|
||||||
date_expired = models.DateTimeField(default=date_expired_default, db_index=True, verbose_name=_('Date expired'))
|
verbose_name=_("Date start"))
|
||||||
|
date_expired = models.DateTimeField(default=date_expired_default, db_index=True,
|
||||||
|
verbose_name=_('Date expired'))
|
||||||
created_by = models.CharField(max_length=128, blank=True, verbose_name=_('Created by'))
|
created_by = models.CharField(max_length=128, blank=True, verbose_name=_('Created by'))
|
||||||
date_created = models.DateTimeField(auto_now_add=True, verbose_name=_('Date created'))
|
date_created = models.DateTimeField(auto_now_add=True, verbose_name=_('Date created'))
|
||||||
from_ticket = models.BooleanField(default=False, verbose_name=_('From ticket'))
|
from_ticket = models.BooleanField(default=False, verbose_name=_('From ticket'))
|
||||||
|
@ -106,6 +113,11 @@ class AssetPermission(OrgModelMixin):
|
||||||
|
|
||||||
objects = AssetPermissionManager.from_queryset(AssetPermissionQuerySet)()
|
objects = AssetPermissionManager.from_queryset(AssetPermissionQuerySet)()
|
||||||
|
|
||||||
|
class SpecialAccount(models.TextChoices):
|
||||||
|
ALL = '@ALL', 'All'
|
||||||
|
INPUT = '@INPUT', 'Input'
|
||||||
|
USER = '@USER', 'User'
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = [('org_id', 'name')]
|
unique_together = [('org_id', 'name')]
|
||||||
verbose_name = _("Asset permission")
|
verbose_name = _("Asset permission")
|
||||||
|
@ -174,14 +186,17 @@ class AssetPermission(OrgModelMixin):
|
||||||
models.Prefetch('assets', queryset=Asset.objects.all().only('id')),
|
models.Prefetch('assets', queryset=Asset.objects.all().only('id')),
|
||||||
).order_by()
|
).order_by()
|
||||||
|
|
||||||
def get_all_assets(self):
|
def get_all_assets(self, flat=False):
|
||||||
from assets.models import Node
|
from assets.models import Node
|
||||||
nodes_keys = self.nodes.all().values_list('key', flat=True)
|
nodes_keys = self.nodes.all().values_list('key', flat=True)
|
||||||
asset_ids = set(self.assets.all().values_list('id', flat=True))
|
asset_ids = set(self.assets.all().values_list('id', flat=True))
|
||||||
nodes_asset_ids = Node.get_nodes_all_asset_ids_by_keys(nodes_keys)
|
nodes_asset_ids = Node.get_nodes_all_asset_ids_by_keys(nodes_keys)
|
||||||
asset_ids.update(nodes_asset_ids)
|
asset_ids.update(nodes_asset_ids)
|
||||||
assets = Asset.objects.filter(id__in=asset_ids)
|
if flat:
|
||||||
return assets
|
return asset_ids
|
||||||
|
else:
|
||||||
|
assets = Asset.objects.filter(id__in=asset_ids)
|
||||||
|
return assets
|
||||||
|
|
||||||
def users_display(self):
|
def users_display(self):
|
||||||
names = [user.username for user in self.users.all()]
|
names = [user.username for user in self.users.all()]
|
||||||
|
@ -199,6 +214,94 @@ class AssetPermission(OrgModelMixin):
|
||||||
names = [node.full_value for node in self.nodes.all()]
|
names = [node.full_value for node in self.nodes.all()]
|
||||||
return names
|
return names
|
||||||
|
|
||||||
|
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)
|
||||||
|
return accounts
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_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_permissions(cls, user=None, asset=None, account=None):
|
||||||
|
""" 获取同时包含 用户-资产-账号 的授权规则 """
|
||||||
|
assetperm_ids = []
|
||||||
|
if user:
|
||||||
|
user_assetperm_ids = cls.filter_permissions_by_user(user, flat=True)
|
||||||
|
assetperm_ids.append(user_assetperm_ids)
|
||||||
|
if asset:
|
||||||
|
asset_assetperm_ids = cls.filter_permissions_by_asset(asset, flat=True)
|
||||||
|
assetperm_ids.append(asset_assetperm_ids)
|
||||||
|
if account:
|
||||||
|
account_assetperm_ids = cls.filter_permissions_by_account(account, flat=True)
|
||||||
|
assetperm_ids.append(account_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
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def filter_permissions_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)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
if flat:
|
||||||
|
return assetperm_ids
|
||||||
|
else:
|
||||||
|
assetperms = cls.objects.filter(id__in=assetperm_ids).valid()
|
||||||
|
return assetperms
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def filter_permissions_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)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
if flat:
|
||||||
|
return assetperm_ids
|
||||||
|
else:
|
||||||
|
assetperms = cls.objects.filter(id__in=assetperm_ids).valid()
|
||||||
|
return assetperms
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def filter_permissions_by_account(cls, account, flat=False):
|
||||||
|
assetperms = cls.objects.filter(accounts__contains=account).valid()
|
||||||
|
if flat:
|
||||||
|
assetperm_ids = assetperms.values_list('id', flat=True)
|
||||||
|
return assetperm_ids
|
||||||
|
else:
|
||||||
|
return assetperms
|
||||||
|
|
||||||
|
|
||||||
class UserAssetGrantedTreeNodeRelation(OrgModelMixin, FamilyMixin, BaseCreateUpdateModel):
|
class UserAssetGrantedTreeNodeRelation(OrgModelMixin, FamilyMixin, BaseCreateUpdateModel):
|
||||||
class NodeFrom(TextChoices):
|
class NodeFrom(TextChoices):
|
||||||
|
@ -210,7 +313,8 @@ class UserAssetGrantedTreeNodeRelation(OrgModelMixin, FamilyMixin, BaseCreateUpd
|
||||||
node = models.ForeignKey('assets.Node', default=None, on_delete=models.CASCADE,
|
node = models.ForeignKey('assets.Node', default=None, on_delete=models.CASCADE,
|
||||||
db_constraint=False, null=False, related_name='granted_node_rels')
|
db_constraint=False, null=False, related_name='granted_node_rels')
|
||||||
node_key = models.CharField(max_length=64, verbose_name=_("Key"), db_index=True)
|
node_key = models.CharField(max_length=64, verbose_name=_("Key"), db_index=True)
|
||||||
node_parent_key = models.CharField(max_length=64, default='', verbose_name=_('Parent key'), db_index=True)
|
node_parent_key = models.CharField(max_length=64, default='', verbose_name=_('Parent key'),
|
||||||
|
db_index=True)
|
||||||
node_from = models.CharField(choices=NodeFrom.choices, max_length=16, db_index=True)
|
node_from = models.CharField(choices=NodeFrom.choices, max_length=16, db_index=True)
|
||||||
node_assets_amount = models.IntegerField(default=0)
|
node_assets_amount = models.IntegerField(default=0)
|
||||||
|
|
||||||
|
@ -297,4 +401,3 @@ class PermedAsset(Asset):
|
||||||
('view_userassets', _('Can view user assets')),
|
('view_userassets', _('Can view user assets')),
|
||||||
('view_usergroupassets', _('Can view usergroup assets')),
|
('view_usergroupassets', _('Can view usergroup assets')),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -4,20 +4,19 @@
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from assets.models import Node, Asset, Platform
|
from assets.models import Node, Asset, Platform, Account
|
||||||
from perms.serializers.permission import ActionsField
|
from perms.serializers.permission import ActionsField
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'NodeGrantedSerializer',
|
'NodeGrantedSerializer',
|
||||||
'AssetGrantedSerializer',
|
'AssetGrantedSerializer',
|
||||||
'ActionsSerializer',
|
'ActionsSerializer',
|
||||||
|
'AccountsGrantedSerializer'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class AssetGrantedSerializer(serializers.ModelSerializer):
|
class AssetGrantedSerializer(serializers.ModelSerializer):
|
||||||
"""
|
""" 被授权资产的数据结构 """
|
||||||
被授权资产的数据结构
|
|
||||||
"""
|
|
||||||
platform = serializers.SlugRelatedField(
|
platform = serializers.SlugRelatedField(
|
||||||
slug_field='name', queryset=Platform.objects.all(), label=_("Platform")
|
slug_field='name', queryset=Platform.objects.all(), label=_("Platform")
|
||||||
)
|
)
|
||||||
|
@ -44,3 +43,14 @@ class NodeGrantedSerializer(serializers.ModelSerializer):
|
||||||
class ActionsSerializer(serializers.Serializer):
|
class ActionsSerializer(serializers.Serializer):
|
||||||
actions = ActionsField(read_only=True)
|
actions = ActionsField(read_only=True)
|
||||||
|
|
||||||
|
|
||||||
|
class AccountsGrantedSerializer(serializers.ModelSerializer):
|
||||||
|
""" 授权的账号序列类 """
|
||||||
|
|
||||||
|
# Todo: 添加前端登录逻辑中需要的一些字段,比如:是否需要手动输入密码
|
||||||
|
# need_manual = serializers.BooleanField(label=_('Need manual input'))
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Account
|
||||||
|
fields = ['id', 'name', 'username']
|
||||||
|
read_only_fields = fields
|
||||||
|
|
|
@ -5,7 +5,6 @@ from rest_framework_bulk.routes import BulkRouter
|
||||||
|
|
||||||
from .. import api
|
from .. import api
|
||||||
|
|
||||||
# v3 Done
|
|
||||||
router = BulkRouter()
|
router = BulkRouter()
|
||||||
router.register('asset-permissions', api.AssetPermissionViewSet, 'asset-permission')
|
router.register('asset-permissions', api.AssetPermissionViewSet, 'asset-permission')
|
||||||
router.register('asset-permissions-users-relations', api.AssetPermissionUserRelationViewSet, 'asset-permissions-users-relation')
|
router.register('asset-permissions-users-relations', api.AssetPermissionUserRelationViewSet, 'asset-permissions-users-relation')
|
||||||
|
@ -14,42 +13,31 @@ router.register('asset-permissions-assets-relations', api.AssetPermissionAssetRe
|
||||||
router.register('asset-permissions-nodes-relations', api.AssetPermissionNodeRelationViewSet, 'asset-permissions-nodes-relation')
|
router.register('asset-permissions-nodes-relations', api.AssetPermissionNodeRelationViewSet, 'asset-permissions-nodes-relation')
|
||||||
|
|
||||||
user_permission_urlpatterns = [
|
user_permission_urlpatterns = [
|
||||||
# 统一说明:
|
|
||||||
# `<uuid:pk>`: `User.pk`
|
|
||||||
# 直接授权:在 `AssetPermission` 中关联的对象
|
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
|
||||||
# 以 serializer 格式返回
|
# 以 serializer 格式返回
|
||||||
path('<uuid:pk>/assets/', api.UserAllGrantedAssetsApi.as_view(), name='user-assets'),
|
path('<uuid:pk>/assets/', api.UserAllGrantedAssetsApi.as_view(), name='user-assets'),
|
||||||
path('assets/', api.MyAllGrantedAssetsApi.as_view(), name='my-assets'),
|
path('assets/', api.MyAllGrantedAssetsApi.as_view(), name='my-assets'),
|
||||||
|
|
||||||
# Tree Node 的数据格式返回
|
# Tree Node 的数据格式返回
|
||||||
path('<uuid:pk>/assets/tree/', api.UserDirectGrantedAssetsAsTreeApi.as_view(), name='user-assets-as-tree'),
|
path('<uuid:pk>/assets/tree/', api.UserDirectGrantedAssetsAsTreeApi.as_view(), name='user-assets-as-tree'),
|
||||||
path('assets/tree/', api.MyAllAssetsAsTreeApi.as_view(), name='my-assets-as-tree'),
|
path('assets/tree/', api.MyAllAssetsAsTreeApi.as_view(), name='my-assets-as-tree'),
|
||||||
path('ungroup/assets/tree/', api.MyUngroupAssetsAsTreeApi.as_view(), name='my-ungroup-assets-as-tree'),
|
path('ungroup/assets/tree/', api.MyUngroupAssetsAsTreeApi.as_view(), name='my-ungroup-assets-as-tree'),
|
||||||
# ^--------------------------------------------------------^
|
|
||||||
|
|
||||||
# 获取用户所有`直接授权的节点`与`直接授权资产`关联的节点
|
# 获取用户所有`直接授权的节点`与`直接授权资产`关联的节点
|
||||||
# 以 serializer 格式返回
|
# 以 serializer 格式返回
|
||||||
path('<uuid:pk>/nodes/', api.UserGrantedNodesForAdminApi.as_view(), name='user-nodes'),
|
path('<uuid:pk>/nodes/', api.UserGrantedNodesApi.as_view(), name='user-nodes'),
|
||||||
path('nodes/', api.MyGrantedNodesApi.as_view(), name='my-nodes'),
|
path('nodes/', api.MyGrantedNodesApi.as_view(), name='my-nodes'),
|
||||||
|
|
||||||
# 以 Tree Node 的数据格式返回
|
# 以 Tree Node 的数据格式返回
|
||||||
path('<uuid:pk>/nodes/tree/', api.MyGrantedNodesAsTreeApi.as_view(), name='user-nodes-as-tree'),
|
path('<uuid:pk>/nodes/tree/', api.MyGrantedNodesAsTreeApi.as_view(), name='user-nodes-as-tree'),
|
||||||
path('nodes/tree/', api.MyGrantedNodesAsTreeApi.as_view(), name='my-nodes-as-tree'),
|
path('nodes/tree/', api.MyGrantedNodesAsTreeApi.as_view(), name='my-nodes-as-tree'),
|
||||||
# ^--------------------------------------------------------^
|
|
||||||
|
|
||||||
# 一层一层的获取用户授权的节点,
|
# 一层一层的获取用户授权的节点,
|
||||||
# 以 Serializer 的数据格式返回
|
# 以 Serializer 的数据格式返回
|
||||||
path('<uuid:pk>/nodes/children/', api.UserGrantedNodeChildrenForAdminApi.as_view(), name='user-nodes-children'),
|
path('<uuid:pk>/nodes/children/', api.UserGrantedNodeChildrenForAdminApi.as_view(), name='user-nodes-children'),
|
||||||
path('nodes/children/', api.MyGrantedNodeChildrenApi.as_view(), name='my-nodes-children'),
|
path('nodes/children/', api.MyGrantedNodeChildrenApi.as_view(), name='my-nodes-children'),
|
||||||
|
|
||||||
# 以 Tree Node 的数据格式返回
|
# 以 Tree Node 的数据格式返回
|
||||||
path('<uuid:pk>/nodes/children/tree/', api.UserGrantedNodeChildrenAsTreeForAdminApi.as_view(), name='user-nodes-children-as-tree'),
|
path('<uuid:pk>/nodes/children/tree/', api.UserGrantedNodeChildrenAsTreeForAdminApi.as_view(), name='user-nodes-children-as-tree'),
|
||||||
# 部分调用位置
|
# 部分调用位置
|
||||||
# - 普通用户 -> 我的资产 -> 展开节点 时调用
|
# - 普通用户 -> 我的资产 -> 展开节点 时调用
|
||||||
path('nodes/children/tree/', api.MyGrantedNodeChildrenAsTreeApi.as_view(), name='my-nodes-children-as-tree'),
|
path('nodes/children/tree/', api.MyGrantedNodeChildrenAsTreeApi.as_view(), name='my-nodes-children-as-tree'),
|
||||||
# ^--------------------------------------------------------^
|
|
||||||
|
|
||||||
# 此接口会返回整棵树
|
# 此接口会返回整棵树
|
||||||
# 普通用户 -> 命令执行 -> 左侧树
|
# 普通用户 -> 命令执行 -> 左侧树
|
||||||
|
@ -75,6 +63,11 @@ user_permission_urlpatterns = [
|
||||||
# Asset System users
|
# Asset System users
|
||||||
path('<uuid:pk>/assets/<uuid:asset_id>/system-users/', api.UserGrantedAssetSystemUsersForAdminApi.as_view(), name='user-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'),
|
path('assets/<uuid:asset_id>/system-users/', api.MyGrantedAssetSystemUsersApi.as_view(), name='my-asset-system-users'),
|
||||||
|
|
||||||
|
# Todo: 增加
|
||||||
|
# 获取所有和资产相关联的账号列表
|
||||||
|
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')
|
||||||
]
|
]
|
||||||
|
|
||||||
user_group_permission_urlpatterns = [
|
user_group_permission_urlpatterns = [
|
||||||
|
|
|
@ -918,6 +918,21 @@ class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, AbstractUser):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def get_groups(self, flat=False):
|
||||||
|
from users.models import UserGroup
|
||||||
|
usergroup_ids = self.groups.through.objects\
|
||||||
|
.filter(user_id=self.id)\
|
||||||
|
.distinct()\
|
||||||
|
.values_list('usergroup_id', flat=True)
|
||||||
|
usergroups = UserGroup.objects.filter(id__in=usergroup_ids)
|
||||||
|
if flat:
|
||||||
|
usergroup_ids = usergroups.values_list('id', flat=True)
|
||||||
|
return usergroup_ids
|
||||||
|
else:
|
||||||
|
return usergroups
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class UserPasswordHistory(models.Model):
|
class UserPasswordHistory(models.Model):
|
||||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
|
||||||
|
# >>> Django 环境配置
|
||||||
|
import django
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if os.path.exists('../apps'):
|
||||||
|
sys.path.insert(0, '../apps')
|
||||||
|
elif os.path.exists('./apps'):
|
||||||
|
sys.path.insert(0, './apps')
|
||||||
|
|
||||||
|
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
APPS_DIR = os.path.join(BASE_DIR, 'apps')
|
||||||
|
sys.path.insert(0, APPS_DIR)
|
||||||
|
|
||||||
|
os.environ.setdefault('PYTHONOPTIMIZE', '1')
|
||||||
|
if os.getuid() == 0:
|
||||||
|
os.environ.setdefault('C_FORCE_ROOT', '1')
|
||||||
|
|
||||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "jumpserver.settings")
|
||||||
|
django.setup()
|
||||||
|
|
||||||
|
# <<<
|
||||||
|
|
||||||
|
|
||||||
|
class Generator(object):
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def generate_assets(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
pass
|
Loading…
Reference in New Issue