吴晓阳
发布于 2025-03-09 / 11 阅读
0

Admin.Net按钮权限自动生成器方法

title: Admin.Net按钮权限自动生成器方法
authors: shiningrise
tags: [dotnet]
image:
description:

//PermissionAttribute.cs
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Admin.NET.Application;

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class PermissionAttribute : Attribute
{
    /// <summary>
    /// 父Id
    /// </summary>
    public long Pid { get; set; }

    /// <summary>
    /// 菜单类型(1目录 2菜单 3按钮)
    /// </summary>
    public MenuTypeEnum Type { get; set; } = MenuTypeEnum.Menu;

    /// <summary>
    /// 路由名称
    /// </summary>
    [MaxLength(64)]
    public string? Name { get; set; }

    /// <summary>
    /// 路由地址
    /// </summary>
    [MaxLength(128)]
    public string? Path { get; set; }

    /// <summary>
    /// 组件路径
    /// </summary>
    [MaxLength(128)]
    public string? Component { get; set; }

    /// <summary>
    /// 权限标识
    /// </summary>
    [MaxLength(128)]
    public string? Permission { get; set; }

    /// <summary>
    /// 菜单名称
    /// </summary>
    [Required, MaxLength(64)]
    public virtual string Title { get; set; }

    /// <summary>
    /// 图标
    /// </summary>
    [MaxLength(128)]
    public string? Icon { get; set; } = "ele-Menu";

    /// <summary>
    /// 是否隐藏
    /// </summary>
    public bool IsHide { get; set; }

    /// <summary>
    /// 是否缓存
    /// </summary>
    public bool IsKeepAlive { get; set; } = true;

    /// <summary>
    /// 是否固定
    /// </summary>
    public bool IsAffix { get; set; }

    /// <summary>
    /// 排序
    /// </summary>
    public int OrderNo { get; set; } = 100;

    /// <summary>
    /// 状态
    /// </summary>
    public StatusEnum Status { get; set; } = StatusEnum.Enable;

    /// <summary>
    /// 备注
    /// </summary>
    [MaxLength(256)]
    public string? Remark { get; set; }
}
//IPermissionInitializer.cs
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

namespace Admin.NET.Application;

public interface IPermissionInitializer
{
    void Initialize();
}
//PermissionInitializer.cs
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

/* 按钮权限自动生成器方法介绍:
  在服务类上加[Permission( Title = "菜单名称")]
  在方法上加上[Permission()]
  在Startup.cs文件中加
  services.AddScoped<IPermissionInitializer,PermissionInitializer>();
 
       using (var scope = app.ApplicationServices.CreateScope())
        {
            var initializer = scope.ServiceProvider.GetRequiredService<IPermissionInitializer>();
            initializer.Initialize();
        }
 */
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Admin.NET.Application;

public class PermissionInitializer : IPermissionInitializer
{
    private readonly IServiceProvider _serviceProvider;
    private readonly ILogger<PermissionInitializer> _logger;

    public PermissionInitializer(
        IServiceProvider serviceProvider,
        ILogger<PermissionInitializer> logger)
    {
        _serviceProvider = serviceProvider;
        _logger = logger;
    }

    public void Initialize()
    {
        try
        {
            using (var scope = _serviceProvider.CreateScope())
            {
                // 获取SqlSugar仓储
                var menuRepository = scope.ServiceProvider.GetRequiredService<SqlSugarRepository<SysMenu>>();

                _logger.LogInformation("开始扫描控制器并初始化菜单按钮权限...");

                // 获取所有继承自IDynamicApiController的类型
                var controllerTypes = AppDomain.CurrentDomain.GetAssemblies()
                    .SelectMany(a => a.GetTypes())
                    .Where(t => t.IsClass && !t.IsAbstract && typeof(IDynamicApiController).IsAssignableFrom(t))
                    .ToList();

                var menus = new List<SysMenu>();

                foreach (var controllerType in controllerTypes)
                {
                    // 处理控制器级别的权限
                    var controllerPermissions = controllerType.GetCustomAttributes<PermissionAttribute>().ToList();
                    if (!controllerPermissions.Any())
                    {
                        continue;
                    }
                    var menuTitle = controllerPermissions[0];
                    var menu = menuRepository.GetFirst(m => m.Title == menuTitle.Title && m.Type == MenuTypeEnum.Menu);
                    if (menu == null)
                    {
                        continue;
                    }

                    // 处理方法级别的权限
                    var methods = controllerType.GetMethods(BindingFlags.Public | BindingFlags.Instance)
                        .Where(m => m.DeclaringType == controllerType);

                    foreach (var method in methods)
                    {
                        var methodPermissions = method.GetCustomAttributes<PermissionAttribute>();
                        foreach (var permAttr in methodPermissions)
                        {
                            if (string.IsNullOrWhiteSpace(permAttr.Title))
                            {
                                var displayNameAttributes = method.GetCustomAttributes<DisplayNameAttribute>().ToList();
                                var displayNameAttribute = displayNameAttributes.FirstOrDefault();
                                permAttr.Title = displayNameAttribute?.DisplayName ?? method.Name;
                            }
                            if (string.IsNullOrWhiteSpace(permAttr.Permission))
                            {
                                permAttr.Permission = controllerType.Name.Replace("Service", "").ToFirstLetterLowerCase() + "/" + method.Name.ToFirstLetterLowerCase();
                            }
                            var methodMenu = menuRepository.GetFirst(m => m.Title == permAttr.Title && m.Type == MenuTypeEnum.Btn && m.Pid == menu.Id);
                            if (methodMenu != null)
                            {
                                continue;
                            }
                            // 对于方法级别的权限,通常是按钮类型
                            methodMenu = new SysMenu
                            {
                                Pid = menu.Id,
                                Type = MenuTypeEnum.Btn, // 方法级别的权限通常是按钮
                                Name = permAttr.Name,
                                Path = permAttr.Path,
                                Component = permAttr.Component,
                                Permission = permAttr.Permission,
                                Title = permAttr.Title,
                                Icon = permAttr.Icon,
                                IsHide = permAttr.IsHide,
                                IsKeepAlive = permAttr.IsKeepAlive,
                                IsAffix = permAttr.IsAffix,
                                OrderNo = permAttr.OrderNo,
                                Status = permAttr.Status,
                                Remark = permAttr.Remark
                            };

                            menus.Add(methodMenu);
                        }
                    }
                }

                // 保存菜单和按钮权限
                if (menus.Any())
                {
                    // 获取现有菜单
                    var existingMenus = menuRepository.GetList();

                    // 过滤掉已存在的菜单和按钮
                    var newMenus = menus
                        .Where(m => !existingMenus.Any(em =>
                            em.Permission == m.Permission &&
                            em.Type == m.Type))
                        .ToList();

                    if (newMenus.Any())
                    {
                        menuRepository.InsertRange(newMenus);
                        _logger.LogInformation($"成功添加{newMenus.Count}个新的菜单和按钮权限");
                    }
                }

                _logger.LogInformation("菜单按钮权限初始化完成");
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "初始化菜单按钮权限时发生错误");
        }
    }
}