diff --git a/apps/jumpserver/conf.py b/apps/jumpserver/conf.py index 0deef705e..4ef326a36 100644 --- a/apps/jumpserver/conf.py +++ b/apps/jumpserver/conf.py @@ -311,6 +311,7 @@ defaults = { 'REDIS_PASSWORD': '', 'REDIS_DB_CELERY': 3, 'REDIS_DB_CACHE': 4, + 'REDIS_DB_SESSION': 5, 'CAPTCHA_TEST_MODE': None, 'TOKEN_EXPIRATION': 3600 * 24, 'DISPLAY_PER_PAGE': 25, @@ -348,6 +349,7 @@ defaults = { 'HTTP_BIND_HOST': '0.0.0.0', 'HTTP_LISTEN_PORT': 8080, 'LOGIN_LOG_KEEP_DAYS': 90, + 'ASSETS_PERM_CACHE_TIME': 3600, } diff --git a/apps/jumpserver/settings.py b/apps/jumpserver/settings.py index 324741bd0..1147e07e8 100644 --- a/apps/jumpserver/settings.py +++ b/apps/jumpserver/settings.py @@ -141,6 +141,16 @@ SESSION_COOKIE_DOMAIN = CONFIG.SESSION_COOKIE_DOMAIN CSRF_COOKIE_DOMAIN = CONFIG.CSRF_COOKIE_DOMAIN SESSION_COOKIE_AGE = CONFIG.SESSION_COOKIE_AGE SESSION_EXPIRE_AT_BROWSER_CLOSE = CONFIG.SESSION_EXPIRE_AT_BROWSER_CLOSE +SESSION_ENGINE = 'redis_sessions.session' +SESSION_REDIS = { + 'host': CONFIG.REDIS_HOST, + 'port': CONFIG.REDIS_PORT, + 'password': CONFIG.REDIS_PASSWORD, + 'db': CONFIG.REDIS_DB_SESSION, + 'prefix': 'auth_session', + 'socket_timeout': 1, + 'retry_on_timeout': False +} MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage' # Database @@ -559,3 +569,6 @@ SWAGGER_SETTINGS = { # Default email suffix EMAIL_SUFFIX = CONFIG.EMAIL_SUFFIX LOGIN_LOG_KEEP_DAYS = CONFIG.LOGIN_LOG_KEEP_DAYS + +# User or user group permission cache time, default 3600 seconds +ASSETS_PERM_CACHE_TIME = CONFIG.ASSETS_PERM_CACHE_TIME diff --git a/apps/perms/api.py b/apps/perms/api.py deleted file mode 100644 index d19f82f3f..000000000 --- a/apps/perms/api.py +++ /dev/null @@ -1,663 +0,0 @@ -# ~*~ coding: utf-8 ~*~ -# - -from django.shortcuts import get_object_or_404 -from django.utils import timezone -from django.db.models import Q -from rest_framework.views import APIView, Response -from rest_framework.generics import ( - ListAPIView, get_object_or_404, RetrieveUpdateAPIView -) -from rest_framework import viewsets -from rest_framework.pagination import LimitOffsetPagination - -from common.permissions import IsValidUser, IsOrgAdmin, IsOrgAdminOrAppUser -from common.tree import TreeNode, TreeNodeSerializer -from common.utils import get_object_or_none -from orgs.mixins import RootOrgViewMixin -from orgs.utils import set_to_root_org -from .utils import ( - AssetPermissionUtil, parse_asset_to_tree_node, parse_node_to_tree_node -) -from .models import AssetPermission -from .hands import ( - AssetGrantedSerializer, User, UserGroup, Asset, Node, - SystemUser, NodeSerializer -) -from . import serializers -from .mixins import AssetsFilterMixin - - -__all__ = [ - 'AssetPermissionViewSet', 'UserGrantedAssetsApi', 'UserGrantedNodesApi', - 'UserGrantedNodesWithAssetsApi', 'UserGrantedNodeAssetsApi', 'UserGroupGrantedAssetsApi', - 'UserGroupGrantedNodesApi', 'UserGroupGrantedNodesWithAssetsApi', 'UserGroupGrantedNodeAssetsApi', - 'ValidateUserAssetPermissionApi', 'AssetPermissionRemoveUserApi', 'AssetPermissionAddUserApi', - 'AssetPermissionRemoveAssetApi', 'AssetPermissionAddAssetApi', 'UserGrantedNodeChildrenApi', - 'UserGrantedNodesWithAssetsAsTreeApi', -] - - -class AssetPermissionViewSet(viewsets.ModelViewSet): - """ - 资产授权列表的增删改查api - """ - queryset = AssetPermission.objects.all() - serializer_class = serializers.AssetPermissionCreateUpdateSerializer - pagination_class = LimitOffsetPagination - filter_fields = ['name'] - permission_classes = (IsOrgAdmin,) - - def get_serializer_class(self): - if self.action in ("list", 'retrieve'): - return serializers.AssetPermissionListSerializer - return self.serializer_class - - def filter_valid(self, queryset): - valid = self.request.query_params.get('is_valid', None) - if valid is None: - return queryset - if valid in ['0', 'N', 'false', 'False']: - valid = False - else: - valid = True - now = timezone.now() - if valid: - queryset = queryset.filter(is_active=True).filter( - date_start__lt=now, date_expired__gt=now, - ) - else: - queryset = queryset.filter( - Q(is_active=False) | - Q(date_start__gt=now) | - Q(date_expired__lt=now) - ) - return queryset - - def filter_system_user(self, queryset): - system_user_id = self.request.query_params.get('system_user_id') - system_user_name = self.request.query_params.get('system_user') - if system_user_id: - system_user = get_object_or_none(SystemUser, pk=system_user_id) - elif system_user_name: - system_user = get_object_or_none(SystemUser, name=system_user_name) - else: - return queryset - if not system_user: - return queryset.none() - queryset = queryset.filter(system_users=system_user) - return queryset - - def filter_node(self, queryset): - node_id = self.request.query_params.get('node_id') - node_name = self.request.query_params.get('node') - if node_id: - node = get_object_or_none(Node, pk=node_id) - elif node_name: - node = get_object_or_none(Node, name=node_name) - else: - return queryset - if not node: - return queryset.none() - nodes = node.get_ancestor(with_self=True) - queryset = queryset.filter(nodes__in=nodes) - return queryset - - def filter_asset(self, queryset): - asset_id = self.request.query_params.get('asset_id') - hostname = self.request.query_params.get('hostname') - ip = self.request.query_params.get('ip') - if asset_id: - assets = Asset.objects.filter(pk=asset_id) - elif hostname: - assets = Asset.objects.filter(hostname=hostname) - elif ip: - assets = Asset.objects.filter(ip=ip) - else: - return queryset - if not assets: - return queryset.none() - inherit_nodes = set() - for asset in assets: - for node in asset.nodes.all(): - inherit_nodes.update(set(node.get_ancestor(with_self=True))) - queryset = queryset.filter(Q(assets__in=assets) | Q(nodes__in=inherit_nodes)) - return queryset - - def filter_user(self, queryset): - user_id = self.request.query_params.get('user_id') - username = self.request.query_params.get('username') - if user_id: - user = get_object_or_none(User, pk=user_id) - elif username: - user = get_object_or_none(User, username=username) - else: - return queryset - if not user: - return queryset.none() - - def filter_user_group(self, queryset): - user_group_id = self.request.query_params.get('user_group_id') - user_group_name = self.request.query_params.get('user_group') - if user_group_id: - group = get_object_or_none(UserGroup, pk=user_group_id) - elif user_group_name: - group = get_object_or_none(UserGroup, name=user_group_name) - else: - return queryset - if not group: - return queryset.none() - queryset = queryset.filter(user_groups=group) - return queryset - - def filter_keyword(self, queryset): - keyword = self.request.query_params.get('search') - if not keyword: - return queryset - queryset = queryset.filter(name__icontains=keyword) - return queryset - - def filter_queryset(self, queryset): - queryset = super().filter_queryset(queryset) - queryset = self.filter_valid(queryset) - queryset = self.filter_keyword(queryset) - queryset = self.filter_asset(queryset) - queryset = self.filter_node(queryset) - queryset = self.filter_system_user(queryset) - queryset = self.filter_user_group(queryset) - return queryset - - def get_queryset(self): - return self.queryset.all() - - -class UserGrantedAssetsApi(AssetsFilterMixin, ListAPIView): - """ - 用户授权的所有资产 - """ - permission_classes = (IsOrgAdminOrAppUser,) - serializer_class = AssetGrantedSerializer - pagination_class = LimitOffsetPagination - - def change_org_if_need(self): - if self.request.user.is_superuser or \ - self.request.user.is_app or \ - self.kwargs.get('pk') is None: - set_to_root_org() - - def get_queryset(self): - self.change_org_if_need() - user_id = self.kwargs.get('pk', '') - queryset = [] - - if user_id: - user = get_object_or_404(User, id=user_id) - else: - user = self.request.user - - util = AssetPermissionUtil(user) - for k, v in util.get_assets().items(): - system_users_granted = [s for s in v if s.protocol == k.protocol] - k.system_users_granted = system_users_granted - queryset.append(k) - - return queryset - - def get_permissions(self): - if self.kwargs.get('pk') is None: - self.permission_classes = (IsValidUser,) - return super().get_permissions() - - -class UserGrantedNodesApi(ListAPIView): - """ - 查询用户授权的所有节点的API, 如果是超级用户或者是 app,切换到root org - """ - permission_classes = (IsOrgAdminOrAppUser,) - serializer_class = NodeSerializer - - def change_org_if_need(self): - if self.request.user.is_superuser or \ - self.request.user.is_app or \ - self.kwargs.get('pk') is None: - set_to_root_org() - - def get_queryset(self): - self.change_org_if_need() - user_id = self.kwargs.get('pk', '') - if user_id: - user = get_object_or_404(User, id=user_id) - else: - user = self.request.user - util = AssetPermissionUtil(user) - nodes = util.get_nodes_with_assets() - return nodes.keys() - - def get_permissions(self): - if self.kwargs.get('pk') is None: - self.permission_classes = (IsValidUser,) - return super().get_permissions() - - -class UserGrantedNodesWithAssetsApi(AssetsFilterMixin, ListAPIView): - """ - 用户授权的节点并带着节点下资产的api - """ - permission_classes = (IsOrgAdminOrAppUser,) - serializer_class = serializers.NodeGrantedSerializer - - def change_org_if_need(self): - if self.request.user.is_superuser or \ - self.request.user.is_app or \ - self.kwargs.get('pk') is None: - set_to_root_org() - - def get_queryset(self): - self.change_org_if_need() - user_id = self.kwargs.get('pk', '') - queryset = [] - if not user_id: - user = self.request.user - else: - user = get_object_or_404(User, id=user_id) - - util = AssetPermissionUtil(user) - nodes = util.get_nodes_with_assets() - for node, _assets in nodes.items(): - assets = _assets.keys() - for k, v in _assets.items(): - system_users_granted = [s for s in v if s.protocol == k.protocol] - k.system_users_granted = system_users_granted - node.assets_granted = assets - queryset.append(node) - return queryset - - def sort_assets(self, queryset): - for node in queryset: - node.assets_granted = super().sort_assets(node.assets_granted) - return queryset - - def get_permissions(self): - if self.kwargs.get('pk') is None: - self.permission_classes = (IsValidUser,) - return super().get_permissions() - - -class UserGrantedNodesWithAssetsAsTreeApi(ListAPIView): - serializer_class = TreeNodeSerializer - permission_classes = (IsOrgAdminOrAppUser,) - show_assets = True - system_user_id = None - - def change_org_if_need(self): - if self.request.user.is_superuser or \ - self.request.user.is_app or \ - self.kwargs.get('pk') is None: - set_to_root_org() - - def get(self, request, *args, **kwargs): - self.show_assets = request.query_params.get('show_assets', '1') == '1' - self.system_user_id = request.query_params.get('system_user') - return super().get(request, *args, **kwargs) - - def get_permissions(self): - if self.kwargs.get('pk') is None: - self.permission_classes = (IsValidUser,) - return super().get_permissions() - - def get_queryset(self): - self.change_org_if_need() - user_id = self.kwargs.get('pk', '') - queryset = [] - if not user_id: - user = self.request.user - else: - user = get_object_or_404(User, id=user_id) - util = AssetPermissionUtil(user) - if self.system_user_id: - util.filter_permission_with_system_user(system_user=self.system_user_id) - nodes = util.get_nodes_with_assets() - for node, assets in nodes.items(): - data = parse_node_to_tree_node(node) - queryset.append(data) - if not self.show_assets: - continue - for asset, system_users in assets.items(): - data = parse_asset_to_tree_node(node, asset, system_users) - queryset.append(data) - queryset = sorted(queryset) - return queryset - - -class UserGrantedNodeAssetsApi(AssetsFilterMixin, ListAPIView): - """ - 查询用户授权的节点下的资产的api, 与上面api不同的是,只返回某个节点下的资产 - """ - permission_classes = (IsOrgAdminOrAppUser,) - serializer_class = AssetGrantedSerializer - pagination_class = LimitOffsetPagination - - def change_org_if_need(self): - if self.request.user.is_superuser or \ - self.request.user.is_app or \ - self.kwargs.get('pk') is None: - set_to_root_org() - - def get_queryset(self): - self.change_org_if_need() - user_id = self.kwargs.get('pk', '') - node_id = self.kwargs.get('node_id') - - if user_id: - user = get_object_or_404(User, id=user_id) - else: - user = self.request.user - util = AssetPermissionUtil(user) - node = get_object_or_404(Node, id=node_id) - nodes = util.get_nodes_with_assets() - assets = nodes.get(node, []) - for asset, system_users in assets.items(): - asset.system_users_granted = system_users - - assets = list(assets.keys()) - return assets - - def get_permissions(self): - if self.kwargs.get('pk') is None: - self.permission_classes = (IsValidUser,) - return super().get_permissions() - - -class UserGroupGrantedAssetsApi(ListAPIView): - permission_classes = (IsOrgAdmin,) - serializer_class = AssetGrantedSerializer - - def get_queryset(self): - user_group_id = self.kwargs.get('pk', '') - queryset = [] - - if not user_group_id: - return queryset - - user_group = get_object_or_404(UserGroup, id=user_group_id) - util = AssetPermissionUtil(user_group) - assets = util.get_assets() - for k, v in assets.items(): - k.system_users_granted = v - queryset.append(k) - return queryset - - -class UserGroupGrantedNodesApi(ListAPIView): - permission_classes = (IsOrgAdmin,) - serializer_class = NodeSerializer - - def get_queryset(self): - group_id = self.kwargs.get('pk', '') - queryset = [] - - if group_id: - group = get_object_or_404(UserGroup, id=group_id) - util = AssetPermissionUtil(group) - nodes = util.get_nodes_with_assets() - return nodes.keys() - return queryset - - -class UserGroupGrantedNodesWithAssetsApi(ListAPIView): - permission_classes = (IsOrgAdmin,) - serializer_class = serializers.NodeGrantedSerializer - - def get_queryset(self): - user_group_id = self.kwargs.get('pk', '') - queryset = [] - - if not user_group_id: - return queryset - - user_group = get_object_or_404(UserGroup, id=user_group_id) - util = AssetPermissionUtil(user_group) - nodes = util.get_nodes_with_assets() - for node, _assets in nodes.items(): - assets = _assets.keys() - for asset, system_users in _assets.items(): - asset.system_users_granted = system_users - node.assets_granted = assets - queryset.append(node) - return queryset - - -class UserGroupGrantedNodesWithAssetsAsTreeApi(ListAPIView): - serializer_class = TreeNodeSerializer - permission_classes = (IsOrgAdminOrAppUser,) - show_assets = True - system_user_id = None - - def change_org_if_need(self): - if self.request.user.is_superuser or \ - self.request.user.is_app or \ - self.kwargs.get('pk') is None: - set_to_root_org() - - def get(self, request, *args, **kwargs): - self.show_assets = request.query_params.get('show_assets', '1') == '1' - self.system_user_id = request.query_params.get('system_user') - return super().get(request, *args, **kwargs) - - def get_queryset(self): - self.change_org_if_need() - user_group_id = self.kwargs.get('pk', '') - queryset = [] - group = get_object_or_404(UserGroup, id=user_group_id) - util = AssetPermissionUtil(group) - if self.system_user_id: - util.filter_permission_with_system_user(system_user=self.system_user_id) - nodes = util.get_nodes_with_assets() - for node, assets in nodes.items(): - data = parse_node_to_tree_node(node) - queryset.append(data) - if not self.show_assets: - continue - for asset, system_users in assets.items(): - data = parse_asset_to_tree_node(node, asset, system_users) - queryset.append(data) - queryset = sorted(queryset) - return queryset - - -class UserGroupGrantedNodeAssetsApi(ListAPIView): - permission_classes = (IsOrgAdminOrAppUser,) - serializer_class = AssetGrantedSerializer - - def get_queryset(self): - user_group_id = self.kwargs.get('pk', '') - node_id = self.kwargs.get('node_id') - - user_group = get_object_or_404(UserGroup, id=user_group_id) - node = get_object_or_404(Node, id=node_id) - util = AssetPermissionUtil(user_group) - nodes = util.get_nodes_with_assets() - assets = nodes.get(node, []) - for asset, system_users in assets.items(): - asset.system_users_granted = system_users - return assets - - -class ValidateUserAssetPermissionApi(RootOrgViewMixin, APIView): - permission_classes = (IsOrgAdminOrAppUser,) - - @staticmethod - def get(request): - user_id = request.query_params.get('user_id', '') - asset_id = request.query_params.get('asset_id', '') - system_id = request.query_params.get('system_user_id', '') - - user = get_object_or_404(User, id=user_id) - asset = get_object_or_404(Asset, id=asset_id) - system_user = get_object_or_404(SystemUser, id=system_id) - - util = AssetPermissionUtil(user) - assets_granted = util.get_assets() - if system_user in assets_granted.get(asset, []): - return Response({'msg': True}, status=200) - else: - return Response({'msg': False}, status=403) - - -class AssetPermissionRemoveUserApi(RetrieveUpdateAPIView): - """ - 将用户从授权中移除,Detail页面会调用 - """ - permission_classes = (IsOrgAdmin,) - serializer_class = serializers.AssetPermissionUpdateUserSerializer - queryset = AssetPermission.objects.all() - - def update(self, request, *args, **kwargs): - perm = self.get_object() - serializer = self.serializer_class(data=request.data) - if serializer.is_valid(): - users = serializer.validated_data.get('users') - if users: - perm.users.remove(*tuple(users)) - return Response({"msg": "ok"}) - else: - return Response({"error": serializer.errors}) - - -class AssetPermissionAddUserApi(RetrieveUpdateAPIView): - permission_classes = (IsOrgAdmin,) - serializer_class = serializers.AssetPermissionUpdateUserSerializer - queryset = AssetPermission.objects.all() - - def update(self, request, *args, **kwargs): - perm = self.get_object() - serializer = self.serializer_class(data=request.data) - if serializer.is_valid(): - users = serializer.validated_data.get('users') - if users: - perm.users.add(*tuple(users)) - return Response({"msg": "ok"}) - else: - return Response({"error": serializer.errors}) - - -class AssetPermissionRemoveAssetApi(RetrieveUpdateAPIView): - """ - 将用户从授权中移除,Detail页面会调用 - """ - permission_classes = (IsOrgAdmin,) - serializer_class = serializers.AssetPermissionUpdateAssetSerializer - queryset = AssetPermission.objects.all() - - def update(self, request, *args, **kwargs): - perm = self.get_object() - serializer = self.serializer_class(data=request.data) - if serializer.is_valid(): - assets = serializer.validated_data.get('assets') - if assets: - perm.assets.remove(*tuple(assets)) - return Response({"msg": "ok"}) - else: - return Response({"error": serializer.errors}) - - -class AssetPermissionAddAssetApi(RetrieveUpdateAPIView): - permission_classes = (IsOrgAdmin,) - serializer_class = serializers.AssetPermissionUpdateAssetSerializer - queryset = AssetPermission.objects.all() - - def update(self, request, *args, **kwargs): - perm = self.get_object() - serializer = self.serializer_class(data=request.data) - if serializer.is_valid(): - assets = serializer.validated_data.get('assets') - if assets: - perm.assets.add(*tuple(assets)) - return Response({"msg": "ok"}) - else: - return Response({"error": serializer.errors}) - - -class UserGrantedNodeChildrenApi(ListAPIView): - permission_classes = (IsValidUser,) - serializer_class = serializers.AssetPermissionNodeSerializer - - def change_org_if_need(self): - if self.request.user.is_superuser or \ - self.request.user.is_app or \ - self.kwargs.get('pk') is None: - set_to_root_org() - - def get_children_queryset(self): - util = AssetPermissionUtil(self.request.user) - node_id = self.request.query_params.get('id') - nodes_granted = util.get_nodes_with_assets() - if not nodes_granted: - return [] - root_nodes = [node for node in nodes_granted.keys() if node.is_root()] - - queryset = [] - if node_id and node_id in [str(node.id) for node in nodes_granted]: - node = [node for node in nodes_granted if str(node.id) == node_id][0] - elif len(root_nodes) == 1: - node = root_nodes[0] - node.assets_amount = len(nodes_granted[node]) - queryset.append(node) - else: - for node in root_nodes: - node.assets_amount = len(nodes_granted[node]) - queryset.append(node) - return queryset - - children = [] - for child in node.get_children(): - if child in nodes_granted: - child.assets_amount = len(nodes_granted[node]) - children.append(child) - children = sorted(children, key=lambda x: x.value) - queryset.extend(children) - fake_nodes = [] - for asset, system_users in nodes_granted[node].items(): - fake_node = asset.as_node() - fake_node.assets_amount = 0 - system_users = [s for s in system_users if s.protocol == asset.protocol] - fake_node.asset.system_users_granted = system_users - fake_node.key = node.key + ':0' - fake_nodes.append(fake_node) - fake_nodes = sorted(fake_nodes, key=lambda x: x.value) - queryset.extend(fake_nodes) - return queryset - - def get_search_queryset(self, keyword): - util = AssetPermissionUtil(self.request.user) - nodes_granted = util.get_nodes_with_assets() - queryset = [] - for node, assets in nodes_granted.items(): - matched_assets = [] - node_matched = node.value.lower().find(keyword.lower()) >= 0 - asset_has_matched = False - for asset, system_users in assets.items(): - asset_matched = (asset.hostname.lower().find(keyword.lower()) >= 0) \ - or (asset.ip.find(keyword.lower()) >= 0) - if node_matched or asset_matched: - asset_has_matched = True - fake_node = asset.as_node() - fake_node.assets_amount = 0 - system_users = [s for s in system_users if - s.protocol == asset.protocol] - fake_node.asset.system_users_granted = system_users - fake_node.key = node.key + ':0' - matched_assets.append(fake_node) - if asset_has_matched: - node.assets_amount = len(matched_assets) - queryset.append(node) - queryset.extend(sorted(matched_assets, key=lambda x: x.value)) - return queryset - - def get_queryset(self): - self.change_org_if_need() - keyword = self.request.query_params.get('search') - if keyword: - return self.get_search_queryset(keyword) - else: - return self.get_children_queryset() diff --git a/apps/perms/api/__init__.py b/apps/perms/api/__init__.py new file mode 100644 index 000000000..e90e0262c --- /dev/null +++ b/apps/perms/api/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +# + +from .permission import * +from .user_permission import * +from .user_group_permission import * diff --git a/apps/perms/api/permission.py b/apps/perms/api/permission.py new file mode 100644 index 000000000..c425c90ad --- /dev/null +++ b/apps/perms/api/permission.py @@ -0,0 +1,231 @@ +# -*- coding: utf-8 -*- +# + +from django.utils import timezone +from django.db.models import Q +from rest_framework.views import Response +from rest_framework.generics import RetrieveUpdateAPIView +from rest_framework import viewsets +from rest_framework.pagination import LimitOffsetPagination + +from common.permissions import IsOrgAdmin +from common.utils import get_object_or_none +from ..models import AssetPermission +from ..hands import ( + User, UserGroup, Asset, Node, SystemUser, +) +from .. import serializers + + +__all__ = [ + 'AssetPermissionViewSet', 'AssetPermissionRemoveUserApi', + 'AssetPermissionAddUserApi', 'AssetPermissionRemoveAssetApi', + 'AssetPermissionAddAssetApi', +] + + +class AssetPermissionViewSet(viewsets.ModelViewSet): + """ + 资产授权列表的增删改查api + """ + queryset = AssetPermission.objects.all() + serializer_class = serializers.AssetPermissionCreateUpdateSerializer + pagination_class = LimitOffsetPagination + filter_fields = ['name'] + permission_classes = (IsOrgAdmin,) + + def get_serializer_class(self): + if self.action in ("list", 'retrieve'): + return serializers.AssetPermissionListSerializer + return self.serializer_class + + def filter_valid(self, queryset): + valid = self.request.query_params.get('is_valid', None) + if valid is None: + return queryset + if valid in ['0', 'N', 'false', 'False']: + valid = False + else: + valid = True + now = timezone.now() + if valid: + queryset = queryset.filter(is_active=True).filter( + date_start__lt=now, date_expired__gt=now, + ) + else: + queryset = queryset.filter( + Q(is_active=False) | + Q(date_start__gt=now) | + Q(date_expired__lt=now) + ) + return queryset + + def filter_system_user(self, queryset): + system_user_id = self.request.query_params.get('system_user_id') + system_user_name = self.request.query_params.get('system_user') + if system_user_id: + system_user = get_object_or_none(SystemUser, pk=system_user_id) + elif system_user_name: + system_user = get_object_or_none(SystemUser, name=system_user_name) + else: + return queryset + if not system_user: + return queryset.none() + queryset = queryset.filter(system_users=system_user) + return queryset + + def filter_node(self, queryset): + node_id = self.request.query_params.get('node_id') + node_name = self.request.query_params.get('node') + if node_id: + node = get_object_or_none(Node, pk=node_id) + elif node_name: + node = get_object_or_none(Node, name=node_name) + else: + return queryset + if not node: + return queryset.none() + nodes = node.get_ancestor(with_self=True) + queryset = queryset.filter(nodes__in=nodes) + return queryset + + def filter_asset(self, queryset): + asset_id = self.request.query_params.get('asset_id') + hostname = self.request.query_params.get('hostname') + ip = self.request.query_params.get('ip') + if asset_id: + assets = Asset.objects.filter(pk=asset_id) + elif hostname: + assets = Asset.objects.filter(hostname=hostname) + elif ip: + assets = Asset.objects.filter(ip=ip) + else: + return queryset + if not assets: + return queryset.none() + inherit_nodes = set() + for asset in assets: + for node in asset.nodes.all(): + inherit_nodes.update(set(node.get_ancestor(with_self=True))) + queryset = queryset.filter(Q(assets__in=assets) | Q(nodes__in=inherit_nodes)) + return queryset + + def filter_user(self, queryset): + user_id = self.request.query_params.get('user_id') + username = self.request.query_params.get('username') + if user_id: + user = get_object_or_none(User, pk=user_id) + elif username: + user = get_object_or_none(User, username=username) + else: + return queryset + if not user: + return queryset.none() + + def filter_user_group(self, queryset): + user_group_id = self.request.query_params.get('user_group_id') + user_group_name = self.request.query_params.get('user_group') + if user_group_id: + group = get_object_or_none(UserGroup, pk=user_group_id) + elif user_group_name: + group = get_object_or_none(UserGroup, name=user_group_name) + else: + return queryset + if not group: + return queryset.none() + queryset = queryset.filter(user_groups=group) + return queryset + + def filter_keyword(self, queryset): + keyword = self.request.query_params.get('search') + if not keyword: + return queryset + queryset = queryset.filter(name__icontains=keyword) + return queryset + + def filter_queryset(self, queryset): + queryset = super().filter_queryset(queryset) + queryset = self.filter_valid(queryset) + queryset = self.filter_keyword(queryset) + queryset = self.filter_asset(queryset) + queryset = self.filter_node(queryset) + queryset = self.filter_system_user(queryset) + queryset = self.filter_user_group(queryset) + return queryset + + def get_queryset(self): + return self.queryset.all() + + +class AssetPermissionRemoveUserApi(RetrieveUpdateAPIView): + """ + 将用户从授权中移除,Detail页面会调用 + """ + permission_classes = (IsOrgAdmin,) + serializer_class = serializers.AssetPermissionUpdateUserSerializer + queryset = AssetPermission.objects.all() + + def update(self, request, *args, **kwargs): + perm = self.get_object() + serializer = self.serializer_class(data=request.data) + if serializer.is_valid(): + users = serializer.validated_data.get('users') + if users: + perm.users.remove(*tuple(users)) + return Response({"msg": "ok"}) + else: + return Response({"error": serializer.errors}) + + +class AssetPermissionAddUserApi(RetrieveUpdateAPIView): + permission_classes = (IsOrgAdmin,) + serializer_class = serializers.AssetPermissionUpdateUserSerializer + queryset = AssetPermission.objects.all() + + def update(self, request, *args, **kwargs): + perm = self.get_object() + serializer = self.serializer_class(data=request.data) + if serializer.is_valid(): + users = serializer.validated_data.get('users') + if users: + perm.users.add(*tuple(users)) + return Response({"msg": "ok"}) + else: + return Response({"error": serializer.errors}) + + +class AssetPermissionRemoveAssetApi(RetrieveUpdateAPIView): + """ + 将用户从授权中移除,Detail页面会调用 + """ + permission_classes = (IsOrgAdmin,) + serializer_class = serializers.AssetPermissionUpdateAssetSerializer + queryset = AssetPermission.objects.all() + + def update(self, request, *args, **kwargs): + perm = self.get_object() + serializer = self.serializer_class(data=request.data) + if serializer.is_valid(): + assets = serializer.validated_data.get('assets') + if assets: + perm.assets.remove(*tuple(assets)) + return Response({"msg": "ok"}) + else: + return Response({"error": serializer.errors}) + + +class AssetPermissionAddAssetApi(RetrieveUpdateAPIView): + permission_classes = (IsOrgAdmin,) + serializer_class = serializers.AssetPermissionUpdateAssetSerializer + queryset = AssetPermission.objects.all() + + def update(self, request, *args, **kwargs): + perm = self.get_object() + serializer = self.serializer_class(data=request.data) + if serializer.is_valid(): + assets = serializer.validated_data.get('assets') + if assets: + perm.assets.add(*tuple(assets)) + return Response({"msg": "ok"}) + else: + return Response({"error": serializer.errors}) diff --git a/apps/perms/api/user_group_permission.py b/apps/perms/api/user_group_permission.py new file mode 100644 index 000000000..dede07a0f --- /dev/null +++ b/apps/perms/api/user_group_permission.py @@ -0,0 +1,140 @@ +# -*- coding: utf-8 -*- +# + +from django.shortcuts import get_object_or_404 +from rest_framework.generics import ( + ListAPIView, get_object_or_404, +) + +from common.permissions import IsOrgAdmin, IsOrgAdminOrAppUser +from common.tree import TreeNodeSerializer +from orgs.utils import set_to_root_org +from ..utils import ( + AssetPermissionUtil, parse_asset_to_tree_node, parse_node_to_tree_node +) +from ..hands import ( + AssetGrantedSerializer, UserGroup, Node, NodeSerializer +) +from .. import serializers + + +__all__ = [ + 'UserGroupGrantedAssetsApi', 'UserGroupGrantedNodesApi', + 'UserGroupGrantedNodesWithAssetsApi', 'UserGroupGrantedNodeAssetsApi', + 'UserGroupGrantedNodesWithAssetsAsTreeApi', +] + + +class UserGroupGrantedAssetsApi(ListAPIView): + permission_classes = (IsOrgAdmin,) + serializer_class = AssetGrantedSerializer + + def get_queryset(self): + user_group_id = self.kwargs.get('pk', '') + queryset = [] + + if not user_group_id: + return queryset + + user_group = get_object_or_404(UserGroup, id=user_group_id) + util = AssetPermissionUtil(user_group) + assets = util.get_assets() + for k, v in assets.items(): + k.system_users_granted = v + queryset.append(k) + return queryset + + +class UserGroupGrantedNodesApi(ListAPIView): + permission_classes = (IsOrgAdmin,) + serializer_class = NodeSerializer + + def get_queryset(self): + group_id = self.kwargs.get('pk', '') + queryset = [] + + if group_id: + group = get_object_or_404(UserGroup, id=group_id) + util = AssetPermissionUtil(group) + nodes = util.get_nodes_with_assets() + return nodes.keys() + return queryset + + +class UserGroupGrantedNodesWithAssetsApi(ListAPIView): + permission_classes = (IsOrgAdmin,) + serializer_class = serializers.NodeGrantedSerializer + + def get_queryset(self): + user_group_id = self.kwargs.get('pk', '') + queryset = [] + + if not user_group_id: + return queryset + + user_group = get_object_or_404(UserGroup, id=user_group_id) + util = AssetPermissionUtil(user_group) + nodes = util.get_nodes_with_assets() + for node, _assets in nodes.items(): + assets = _assets.keys() + for asset, system_users in _assets.items(): + asset.system_users_granted = system_users + node.assets_granted = assets + queryset.append(node) + return queryset + + +class UserGroupGrantedNodesWithAssetsAsTreeApi(ListAPIView): + serializer_class = TreeNodeSerializer + permission_classes = (IsOrgAdminOrAppUser,) + show_assets = True + system_user_id = None + + def change_org_if_need(self): + if self.request.user.is_superuser or \ + self.request.user.is_app or \ + self.kwargs.get('pk') is None: + set_to_root_org() + + def get(self, request, *args, **kwargs): + self.show_assets = request.query_params.get('show_assets', '1') == '1' + self.system_user_id = request.query_params.get('system_user') + return super().get(request, *args, **kwargs) + + def get_queryset(self): + self.change_org_if_need() + user_group_id = self.kwargs.get('pk', '') + queryset = [] + group = get_object_or_404(UserGroup, id=user_group_id) + util = AssetPermissionUtil(group) + if self.system_user_id: + util.filter_permission_with_system_user(system_user=self.system_user_id) + nodes = util.get_nodes_with_assets() + for node, assets in nodes.items(): + data = parse_node_to_tree_node(node) + queryset.append(data) + if not self.show_assets: + continue + for asset, system_users in assets.items(): + data = parse_asset_to_tree_node(node, asset, system_users) + queryset.append(data) + queryset = sorted(queryset) + return queryset + + +class UserGroupGrantedNodeAssetsApi(ListAPIView): + permission_classes = (IsOrgAdminOrAppUser,) + serializer_class = AssetGrantedSerializer + + def get_queryset(self): + user_group_id = self.kwargs.get('pk', '') + node_id = self.kwargs.get('node_id') + + user_group = get_object_or_404(UserGroup, id=user_group_id) + node = get_object_or_404(Node, id=node_id) + util = AssetPermissionUtil(user_group) + nodes = util.get_nodes_with_assets() + assets = nodes.get(node, []) + for asset, system_users in assets.items(): + asset.system_users_granted = system_users + return assets diff --git a/apps/perms/api/user_permission.py b/apps/perms/api/user_permission.py new file mode 100644 index 000000000..f00fa8e2e --- /dev/null +++ b/apps/perms/api/user_permission.py @@ -0,0 +1,313 @@ +# -*- coding: utf-8 -*- +# + +from django.shortcuts import get_object_or_404 +from rest_framework.views import APIView, Response +from rest_framework.generics import ( + ListAPIView, get_object_or_404, +) +from rest_framework.pagination import LimitOffsetPagination + +from common.permissions import IsValidUser, IsOrgAdminOrAppUser +from common.tree import TreeNodeSerializer +from orgs.utils import set_to_root_org +from ..utils import ( + AssetPermissionUtil, parse_asset_to_tree_node, parse_node_to_tree_node +) +from ..hands import ( + AssetGrantedSerializer, User, Asset, Node, + SystemUser, NodeSerializer +) +from .. import serializers +from ..mixins import AssetsFilterMixin + + +__all__ = [ + 'UserGrantedAssetsApi', 'UserGrantedNodesApi', + 'UserGrantedNodesWithAssetsApi', 'UserGrantedNodeAssetsApi', + 'ValidateUserAssetPermissionApi', 'UserGrantedNodeChildrenApi', + 'UserGrantedNodesWithAssetsAsTreeApi', +] + + +class UserPermissionMixin: + cache_policy = '0' + + @staticmethod + def change_org_if_need(request, kwargs): + if request.user.is_superuser or \ + request.user.is_app or \ + kwargs.get('pk') is None: + set_to_root_org() + + def dispatch(self, request, *args, **kwargs): + self.change_org_if_need(request, kwargs) + self.cache_policy = request.GET.get('cache_policy', '0') + return super().dispatch(request, *args, **kwargs) + + +class UserGrantedAssetsApi(UserPermissionMixin, AssetsFilterMixin, ListAPIView): + """ + 用户授权的所有资产 + """ + permission_classes = (IsOrgAdminOrAppUser,) + serializer_class = AssetGrantedSerializer + pagination_class = LimitOffsetPagination + + def get_queryset(self): + user_id = self.kwargs.get('pk', '') + queryset = [] + + if user_id: + user = get_object_or_404(User, id=user_id) + else: + user = self.request.user + + util = AssetPermissionUtil(user, cache_policy=self.cache_policy) + assets = util.get_assets() + for k, v in assets.items(): + system_users_granted = [s for s in v if s.protocol == k.protocol] + k.system_users_granted = system_users_granted + queryset.append(k) + return queryset + + def get_permissions(self): + if self.kwargs.get('pk') is None: + self.permission_classes = (IsValidUser,) + return super().get_permissions() + + +class UserGrantedNodesApi(UserPermissionMixin, ListAPIView): + """ + 查询用户授权的所有节点的API, 如果是超级用户或者是 app,切换到root org + """ + permission_classes = (IsOrgAdminOrAppUser,) + serializer_class = NodeSerializer + + def get_queryset(self): + user_id = self.kwargs.get('pk', '') + if user_id: + user = get_object_or_404(User, id=user_id) + else: + user = self.request.user + util = AssetPermissionUtil(user, cache_policy=self.cache_policy) + nodes = util.get_nodes_with_assets() + return nodes.keys() + + def get_permissions(self): + if self.kwargs.get('pk') is None: + self.permission_classes = (IsValidUser,) + return super().get_permissions() + + +class UserGrantedNodesWithAssetsApi(UserPermissionMixin, AssetsFilterMixin, ListAPIView): + """ + 用户授权的节点并带着节点下资产的api + """ + permission_classes = (IsOrgAdminOrAppUser,) + serializer_class = serializers.NodeGrantedSerializer + + def get_queryset(self): + user_id = self.kwargs.get('pk', '') + queryset = [] + if not user_id: + user = self.request.user + else: + user = get_object_or_404(User, id=user_id) + + util = AssetPermissionUtil(user, cache_policy=self.cache_policy) + nodes = util.get_nodes_with_assets() + for node, _assets in nodes.items(): + assets = _assets.keys() + for k, v in _assets.items(): + system_users_granted = [s for s in v if + s.protocol == k.protocol] + k.system_users_granted = system_users_granted + node.assets_granted = assets + queryset.append(node) + return queryset + + def sort_assets(self, queryset): + for node in queryset: + node.assets_granted = super().sort_assets(node.assets_granted) + return queryset + + def get_permissions(self): + if self.kwargs.get('pk') is None: + self.permission_classes = (IsValidUser,) + return super().get_permissions() + + +class UserGrantedNodesWithAssetsAsTreeApi(UserPermissionMixin, ListAPIView): + serializer_class = TreeNodeSerializer + permission_classes = (IsOrgAdminOrAppUser,) + show_assets = True + system_user_id = None + + def get(self, request, *args, **kwargs): + self.show_assets = request.query_params.get('show_assets', '1') == '1' + self.system_user_id = request.query_params.get('system_user') + return super().get(request, *args, **kwargs) + + def get_permissions(self): + if self.kwargs.get('pk') is None: + self.permission_classes = (IsValidUser,) + return super().get_permissions() + + def get_queryset(self): + user_id = self.kwargs.get('pk', '') + queryset = [] + if not user_id: + user = self.request.user + else: + user = get_object_or_404(User, id=user_id) + util = AssetPermissionUtil(user, cache_policy=self.cache_policy) + if self.system_user_id: + util.filter_permission_with_system_user( + system_user=self.system_user_id) + nodes = util.get_nodes_with_assets() + for node, assets in nodes.items(): + data = parse_node_to_tree_node(node) + queryset.append(data) + if not self.show_assets: + continue + for asset, system_users in assets.items(): + data = parse_asset_to_tree_node(node, asset, system_users) + queryset.append(data) + queryset = sorted(queryset) + return queryset + + +class UserGrantedNodeAssetsApi(UserPermissionMixin, AssetsFilterMixin, ListAPIView): + """ + 查询用户授权的节点下的资产的api, 与上面api不同的是,只返回某个节点下的资产 + """ + permission_classes = (IsOrgAdminOrAppUser,) + serializer_class = AssetGrantedSerializer + pagination_class = LimitOffsetPagination + + def get_queryset(self): + user_id = self.kwargs.get('pk', '') + node_id = self.kwargs.get('node_id') + + if user_id: + user = get_object_or_404(User, id=user_id) + else: + user = self.request.user + util = AssetPermissionUtil(user, cache_policy=self.cache_policy) + node = get_object_or_404(Node, id=node_id) + nodes = util.get_nodes_with_assets() + assets = nodes.get(node, []) + for asset, system_users in assets.items(): + asset.system_users_granted = system_users + + assets = list(assets.keys()) + return assets + + def get_permissions(self): + if self.kwargs.get('pk') is None: + self.permission_classes = (IsValidUser,) + return super().get_permissions() + + +class UserGrantedNodeChildrenApi(UserPermissionMixin, ListAPIView): + """ + 获取用户自己授权节点下子节点的api + """ + permission_classes = (IsValidUser,) + serializer_class = serializers.AssetPermissionNodeSerializer + + def get_children_queryset(self): + util = AssetPermissionUtil(self.request.user, cache_policy=self.cache_policy) + node_id = self.request.query_params.get('id') + nodes_granted = util.get_nodes_with_assets() + if not nodes_granted: + return [] + root_nodes = [node for node in nodes_granted.keys() if node.is_root()] + + queryset = [] + if node_id and node_id in [str(node.id) for node in nodes_granted]: + node = [node for node in nodes_granted if str(node.id) == node_id][0] + elif len(root_nodes) == 1: + node = root_nodes[0] + node.assets_amount = len(nodes_granted[node]) + queryset.append(node) + else: + for node in root_nodes: + node.assets_amount = len(nodes_granted[node]) + queryset.append(node) + return queryset + + children = [] + for child in node.get_children(): + if child in nodes_granted: + child.assets_amount = len(nodes_granted[node]) + children.append(child) + children = sorted(children, key=lambda x: x.value) + queryset.extend(children) + fake_nodes = [] + for asset, system_users in nodes_granted[node].items(): + fake_node = asset.as_node() + fake_node.assets_amount = 0 + system_users = [s for s in system_users if s.protocol == asset.protocol] + fake_node.asset.system_users_granted = system_users + fake_node.key = node.key + ':0' + fake_nodes.append(fake_node) + fake_nodes = sorted(fake_nodes, key=lambda x: x.value) + queryset.extend(fake_nodes) + return queryset + + def get_search_queryset(self, keyword): + util = AssetPermissionUtil(self.request.user, cache_policy=self.cache_policy) + nodes_granted = util.get_nodes_with_assets() + queryset = [] + for node, assets in nodes_granted.items(): + matched_assets = [] + node_matched = node.value.lower().find(keyword.lower()) >= 0 + asset_has_matched = False + for asset, system_users in assets.items(): + asset_matched = (asset.hostname.lower().find(keyword.lower()) >= 0) \ + or (asset.ip.find(keyword.lower()) >= 0) + if node_matched or asset_matched: + asset_has_matched = True + fake_node = asset.as_node() + fake_node.assets_amount = 0 + system_users = [s for s in system_users if + s.protocol == asset.protocol] + fake_node.asset.system_users_granted = system_users + fake_node.key = node.key + ':0' + matched_assets.append(fake_node) + if asset_has_matched: + node.assets_amount = len(matched_assets) + queryset.append(node) + queryset.extend(sorted(matched_assets, key=lambda x: x.value)) + return queryset + + def get_queryset(self): + keyword = self.request.query_params.get('search') + if keyword: + return self.get_search_queryset(keyword) + else: + return self.get_children_queryset() + + +class ValidateUserAssetPermissionApi(UserPermissionMixin, APIView): + permission_classes = (IsOrgAdminOrAppUser,) + + def get(self, request): + user_id = request.query_params.get('user_id', '') + asset_id = request.query_params.get('asset_id', '') + system_id = request.query_params.get('system_user_id', '') + + user = get_object_or_404(User, id=user_id) + asset = get_object_or_404(Asset, id=asset_id) + system_user = get_object_or_404(SystemUser, id=system_id) + + util = AssetPermissionUtil(user, cache_policy=self.cache_policy) + assets_granted = util.get_assets() + if system_user in assets_granted.get(asset, []): + return Response({'msg': True}, status=200) + else: + return Response({'msg': False}, status=403) + + diff --git a/apps/perms/utils.py b/apps/perms/utils.py index ba5ebdee1..34330836b 100644 --- a/apps/perms/utils.py +++ b/apps/perms/utils.py @@ -3,6 +3,8 @@ from __future__ import absolute_import, unicode_literals from collections import defaultdict from django.db.models import Q +from django.core.cache import cache +from django.conf import settings from common.utils import get_logger from common.tree import TreeNode @@ -97,10 +99,15 @@ class AssetPermissionUtil: "SystemUser": get_node_permissions, } - def __init__(self, obj): + CACHE_KEY = '_ASSET_PERM_CACHE_{}_{}' + CACHE_TIME = settings.ASSETS_PERM_CACHE_TIME + CACHE_POLICY_MAP = (('0', 'never'), ('1', 'using'), ('2', 'refresh')) + + def __init__(self, obj, cache_policy='0'): self.object = obj self._permissions = None self._assets = None + self.cache_policy = cache_policy @property def permissions(self): @@ -141,7 +148,7 @@ class AssetPermissionUtil: ) return assets - def get_assets(self): + def get_assets_without_cache(self): if self._assets: return self._assets assets = self.get_assets_direct() @@ -155,7 +162,26 @@ class AssetPermissionUtil: self._assets = assets return self._assets - def get_nodes_with_assets(self): + def get_assets_from_cache(self): + cache_key = self.CACHE_KEY.format(str(self.object.id), 'ASSETS') + cached = cache.get(cache_key) + if cached: + return cached + assets = self.get_assets_without_cache() + self.expire_cache() + cache.set(cache_key, assets, self.CACHE_TIME) + return assets + + def get_assets(self): + if self.cache_policy in self.CACHE_POLICY_MAP[1]: + return self.get_assets_from_cache() + elif self.cache_policy in self.CACHE_POLICY_MAP[2]: + self.expire_cache() + return self.get_assets_from_cache() + else: + return self.get_assets_without_cache() + + def get_nodes_with_assets_without_cache(self): """ 返回节点并且包含资产 {"node": {"assets": set("system_user")}} @@ -167,13 +193,60 @@ class AssetPermissionUtil: tree.add_asset(asset, system_users) return tree.get_nodes() - def get_system_users(self): + def get_nodes_with_assets_from_cache(self): + cache_key = self.CACHE_KEY.format(str(self.object.id), 'NODES_WITH_ASSETS') + cached = cache.get(cache_key) + if cached: + return cached + nodes = self.get_nodes_with_assets_without_cache() + self.expire_cache() + cache.set(cache_key, nodes, self.CACHE_TIME) + return nodes + + def get_nodes_with_assets(self): + if self.cache_policy in self.CACHE_POLICY_MAP[1]: + return self.get_nodes_with_assets_from_cache() + elif self.cache_policy in self.CACHE_POLICY_MAP[2]: + self.expire_cache() + return self.get_nodes_with_assets_from_cache() + else: + return self.get_nodes_with_assets_without_cache() + + def get_system_user_without_cache(self): system_users = set() permissions = self.permissions.prefetch_related('system_users') for perm in permissions: system_users.update(perm.system_users.all()) return system_users + def get_system_user_from_cache(self): + cache_key = self.CACHE_KEY.format(str(self.object.id), 'SYSTEM_USER') + cached = cache.get(cache_key) + if cached: + return cached + self.expire_cache() + system_users = self.get_system_user_without_cache() + cache.set(cache_key, system_users, self.CACHE_TIME) + return system_users + + def get_system_users(self): + if self.cache_policy in self.CACHE_POLICY_MAP[1]: + return self.get_system_user_from_cache() + elif self.cache_policy in self.CACHE_POLICY_MAP[2]: + self.expire_cache() + return self.get_system_user_from_cache() + else: + return self.get_system_user_without_cache() + + def expire_cache(self): + cache_key = self.CACHE_KEY.format(str(self.object.id), '*') + cache.delete_pattern(cache_key) + + @classmethod + def expire_all_cache(cls): + cache_key = cls.CACHE_KEY.format('*', '*') + cache.delete_pattern(cache_key) + def is_obj_attr_has(obj, val, attrs=("hostname", "ip", "comment")): if not attrs: diff --git a/apps/users/models/user.py b/apps/users/models/user.py index 52d2c0105..1e84c98e0 100644 --- a/apps/users/models/user.py +++ b/apps/users/models/user.py @@ -310,7 +310,8 @@ class User(AbstractUser): if not isinstance(remote_addr, bytes): remote_addr = remote_addr.encode("utf-8") remote_addr = base64.b16encode(remote_addr) # .replace(b'=', '') - token = cache.get('%s_%s' % (self.id, remote_addr)) + cache_key = '%s_%s' % (self.id, remote_addr) + token = cache.get(cache_key) if not token: token = uuid.uuid4().hex cache.set(token, self.id, expiration) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 3ed0c3497..398f1cdb9 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -80,3 +80,4 @@ python-ldap==3.1.0 tencentcloud-sdk-python==3.0.40 django-radius==1.3.3 ipip-ipdb==1.2.1 +django-redis-sessions==0.6.1