Ask me anything
Ithy Logo
Sign in to save

多组用户权限批量管理系统优化指南

IT vs Business: SharePoint Permissions Strategy- CodeProject

概述

本指南旨在帮助开发者优化现有的共享文件夹权限管理系统,使其能够支持一次性向多个组添加多个用户。通过修改后端逻辑和前端界面,用户可以更高效地管理权限,特别适用于需要批量处理的场景。本指南涵盖了后端Flask应用程序的增强、前端HTML页面的调整以及JSON配置文件的优化。

后端优化

更新权限添加逻辑

为了支持一次性向多个组添加多个用户,需要修改后端的`add_permission` API,使其能够处理多组权限的请求。以下是优化后的Flask后端代码:


from flask_cors import CORS
from flask import Flask, jsonify, request
import json
import subprocess

app = Flask(__name__)
CORS(app)

# 加载共享文件夹配置
def load_config():
    with open('permissions_config.json', 'r', encoding='utf-8') as f:
        return json.load(f)

@app.route('/get-folders', methods=['GET'])
def get_folders():
    try:
        config = load_config()
        folders = list(config.keys())
        return jsonify(folders), 200
    except Exception as e:
        return jsonify({"error": "无法加载共享文件夹路径"}), 500

def get_samaccountname(description):
    """通过 Description 查找 SamAccountName"""
    try:
        query_command = f"Get-ADUser -Filter {{Description -eq '{description}'}} | Select-Object -ExpandProperty SamAccountName"
        query_result = subprocess.run(
            ["powershell", "-Command", query_command],
            capture_output=True,
            text=True
        )
        if query_result.returncode == 0 and query_result.stdout.strip():
            return query_result.stdout.strip()
        else:
            return None  # 未找到用户
    except Exception as e:
        print(f"查询用户失败: {e}")
        return None

@app.route('/add-permission', methods=['POST'])
def add_permission():
    try:
        data = request.json
        folders = data.get('folders', [])  # 支持多个文件夹
        descriptions = data.get('usernames', [])  # 用户输入的 Description 列表
        permission = data.get('permission')

        if not folders or not descriptions or not permission:
            return jsonify({"error": "缺少必要参数"}), 400

        config = load_config()

        results = []
        for folder in folders:
            if folder not in config:
                results.append(f"无效的共享文件夹路径: {folder}")
                continue

            if permission not in config[folder]:
                results.append(f"无效的权限类型: {permission} 在 {folder} 中")
                continue

            group_name = config[folder][permission]

            for description in descriptions:
                samaccountname = get_samaccountname(description)
                if not samaccountname:
                    results.append(f"用户 {description} 不存在。")
                    continue

                # 检查用户是否已在组中
                check_command = f"Get-ADGroupMember -Identity {group_name} | Where-Object {{ $_.SamAccountName -eq '{samaccountname}' }}"
                check_result = subprocess.run(
                    ["powershell", "-Command", check_command],
                    capture_output=True,
                    text=True
                )

                if check_result.returncode == 0 and samaccountname in check_result.stdout:
                    results.append(f"用户 {description} 已经在组 {group_name} 中,无需重复添加。")
                    continue

                # 添加用户到组
                add_command = f"Add-ADGroupMember -Identity {group_name} -Members {samaccountname}"
                print(f"执行命令: {add_command}")
                add_result = subprocess.run(
                    ["powershell", "-Command", add_command],
                    capture_output=True,
                    text=True
                )

                if add_result.returncode == 0:
                    message = f"成功为用户 {description} 添加 {folder} 的 {permission} 权限!"
                    print(message)
                    results.append(message)
                else:
                    error_message = add_result.stderr.strip()
                    if "ObjectNotFound" in error_message:
                        results.append(f"用户 {description} 不存在。")
                    else:
                        results.append(f"用户 {description} 添加失败: {error_message}")

        return jsonify({"message": " | ".join(results)}), 200

    except Exception as e:
        print(f"添加权限失败: {e}")
        return jsonify({"error": "内部服务器错误"}), 500

if __name__ == '__main__':
    app.run(debug=True)
  

代码说明

  • 加载配置文件函数: 创建了一个单独的函数`load_config`来加载`permissions_config.json`,以避免代码重复。
  • 支持多组选择: 在`add_permission`函数中,将`folder`参数替换为`folders`,以支持多个文件夹的选择。
  • 循环处理每个文件夹和用户: 通过嵌套循环,分别处理每个选定的文件夹和每个用户,确保每个用户都被添加到所有选定的组中。
  • 错误处理: 增强了错误处理逻辑,确保每个步骤的失败都能被捕捉并反馈给用户。

前端优化

调整HTML表单结构

为了支持多组选择,需要修改前端的HTML表单,使其能够选择多个文件夹。以下是更新后的前端代码:

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>共享文件夹权限管理</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
    <style>
        body {
            background-color: #f8f9fa;
            padding: 20px;
        }
        h1 {
            margin-bottom: 20px;
        }
        .form-container {
            max-width: 700px;
            margin: auto;
            background: white;
            padding: 30px;
            border-radius: 10px;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
        }
        .btn-submit {
            background-color: #28a745;
            color: white;
        }
        .btn-submit:hover {
            background-color: #218838;
        }
    </style>
</head>
<body>
    <div class="form-container">
        <h1 class="text-center" style="color:#cc9900;">共享文件夹权限管理</h1>
        <form id="permissionForm" onsubmit="event.preventDefault(); submitForm();">
            <div class="mb-3">
                <label for="folders" class="form-label">选择共享文件夹 (可多选):</label>
                <select id="folders" name="folders" class="form-select" multiple required>
                    <option value="" disabled>请选择共享文件夹</option>
                </select>
                <div class="form-text">按住 Ctrl 键 (Windows) 或 Command 键 (Mac) 进行多选。</div>
            </div>
            <div class="mb-3">
                <label for="username" class="form-label">输入用户名(多个用逗号分隔):</label>
                <input type="text" id="username" name="username" class="form-control" placeholder="例如:zuokunlin, anda, zhuoke" required>
            </div>
            <div class="mb-3">
                <label class="form-label">选择权限类型:</label>
                <div class="form-check">
                    <input type="radio" id="readOnly" name="permission" value="ReadOnly" class="form-check-input" required>
                    <label for="readOnly" class="form-check-label">只读</label>
                </div>
                <div class="form-check">
                    <input type="radio" id="readWrite" name="permission" value="ReadWrite" class="form-check-input" required>
                    <label for="readWrite" class="form-check-label">读写</label>
                </div>
            </div>
            <button type="submit" class="btn btn-submit w-100">提交</button>
        </form>
    </div>
    <script>
        // 页面加载时请求共享文件夹路径
        window.onload = function() {
            fetch('http://127.0.0.1:5000/get-folders')
                .then(response => response.json())
                .then(folders => {
                    const folderSelect = document.getElementById('folders');
                    folders.forEach(folder => {
                        const option = document.createElement('option');
                        option.value = folder;
                        option.textContent = folder;
                        folderSelect.appendChild(option);
                    });
                })
                .catch(error => console.error('加载共享路径失败:', error));
        };
        
        // 提交表单
        function submitForm() {
            const folderSelect = document.getElementById('folders');
            const selectedOptions = Array.from(folderSelect.selectedOptions).map(option => option.value);
            const usernames = document.getElementById('username').value.split(',').map(user => user.trim());
            const permission = document.querySelector('input[name="permission"]:checked').value;
            
            fetch('http://127.0.0.1:5000/add-permission', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ folders: selectedOptions, usernames: usernames, permission: permission })
            })
            .then(response => {
                if (!response.ok) {
                    return response.json().then(data => {
                        throw new Error(data.error || '未知错误');
                    });
                }
                return response.json();
            })
            .then(data => {
                alert(data.message);
            })
            .catch(error => {
                alert(`操作失败: ${error.message}`);
                console.error('请求失败:', error);
            });
        }
    </script>
</body>
</html>
  

代码说明

  • 多选下拉列表: 将``元素的`multiple`属性设置为支持多选,并添加提示文本说明如何进行多选操作。
  • JavaScript逻辑更新: 在`submitForm`函数中,使用`selectedOptions`数组获取所有被选中的文件夹,并在请求体中发送`folders`数组。
  • 用户输入处理: 保持对用户名输入的处理方式不变,支持逗号分隔的多个用户名。
  • 权限类型选择: 保持单选按钮的设计,用户选择一种权限类型即可。

JSON配置文件优化

确保`permissions_config.json`包含所有需要管理的共享文件夹及其对应的权限组。以下是一个示例配置:


{
    "\\\\pubnas\\Private": {
        "ReadOnly": "dorisart-read",
        "ReadWrite": "dorisart-wr"
    },
    "\\\\box\\ArtAsset": {
        "ReadOnly": "ArtAsset-R",
        "ReadWrite": "ArtAsset"
    },
    "\\\\box\\ArtCenterToolset": {
        "ReadOnly": "ArtCenterToolset_R",
        "ReadWrite": "ArtCenterToolset_RW"
    },
    "\\\\box\\Project\\UE4": {
        "ReadOnly": "",
        "ReadWrite": "proj_UE4"
    },
    "\\\\box\\Department\\PublishingCenter\\VideoLibrary": {
        "ReadOnly": "BOX_Pub_VideoLibrary-R",
        "ReadWrite": "BOX_Pub_VideoLibrary"
    },
    "\\\\box\\Department\\PublishingCenter\\10-发行中心资料": {
        "ReadOnly": "Publishing-R",
        "ReadWrite": "pub_10_rw"
    }
}
  

代码说明

  • 结构: JSON文件中每个键代表一个共享文件夹路径,值为一个对象,包含不同权限类型对应的组名称。
  • 灵活性: 通过调整JSON文件,可以轻松添加或删除共享文件夹及其权限组,增强了系统的可维护性。

完整系统运行流程

  1. 前端选择多组文件夹和输入多个用户名: 用户在前端界面中选择一个或多个共享文件夹,并输入多个用户名(以逗号分隔)。
  2. 提交请求到后端: 用户点击“提交”按钮后,前端将所选文件夹、用户名和权限类型发送到后端API。
  3. 后端处理请求: 后端接收请求,遍历每个文件夹和用户名,执行添加用户到指定组的操作,同时处理可能出现的错误。
  4. 返回结果反馈: 后端将处理结果返回给前端,前端通过弹窗向用户展示操作结果。

最佳实践与建议

  • 输入验证: 在前端和后端都应加强对用户输入的验证,确保数据的有效性和安全性,防止潜在的注入攻击。
  • 错误处理: 提供详细的错误信息有助于快速定位问题,但同时要注意不要泄露敏感信息。可以在生产环境中限制错误信息的详细程度。
  • 用户体验: 在处理大批量请求时,可以考虑添加进度条或加载指示器,提升用户体验。
  • 日志记录: 后端应记录关键操作和错误信息,便于日后审计和问题排查。
  • 权限管理: 确保只有授权用户可以访问和操作该权限管理系统,保护共享文件夹的安全。

结论

通过上述后端和前端的优化,权限管理系统现已具备批量向多个组添加多个用户的能力,极大提升了管理效率。作为新手,建议仔细阅读并理解每一部分代码的功能和逻辑,并在测试环境中进行充分测试,确保系统的稳定性和安全性。在未来,可以进一步扩展功能,如添加权限删除、权限修改等,以满足更复杂的需求。


Last updated January 7, 2025

AI-assisted research. Sources, methodology and corrections · Source-checked guides and tools · Explore published answers

Ask Ithy AI