EasyAdminBlazor

EasyAdminBlazor 是一个基于 .NET 10 + Blazor 技术栈的企业级后台管理框架,由 BootstrapBlazor 组件库驱动 UI,FreeSql 提供数据访问能力。功能全面、开箱即用、扩展灵活,是个人开发者接私活、外包项目的利器。

🌐 官方网站https://easyadmim.wang-zhan.com.cn


✨ 核心特性

🧩 模块化架构

核心功能与扩展功能解耦,通过 NuGet 扩展按需安装,避免功能臃肿:

模块 说明
用户管理 用户增删改查、状态管理、多端登录检测
角色管理 基于角色的权限分配、管理员标识
菜单管理 无限级菜单树、按钮级权限、可视化配置
组织架构 树形部门管理、数据权限隔离
配置管理 系统参数动态配置,支持数据库存储
字典管理 通用字典表,支持下拉/多选/级联
日志管理 操作日志、登录日志、错误日志,自动记录
文件管理 本地文件上传/下载、图片压缩/WebP 转换、分组管理

🌐 多租户(SaaS)

  • 独立数据库:租户使用独立数据库
  • 按域名解析:根据请求的 Host 自动识别当前租户,零配置切换
  • 菜单权限隔离:每个租户可独立分配功能菜单
  • 文件存储隔离:上传文件按租户 code 分目录存储

🌍 多语言

内置本地化支持,可动态切换界面语言,满足国际化需求。

💬 实时聊天

基于 SignalR 实现站内即时通讯,支持消息实时推送、未读提醒。

📋 计划任务

集成 FreeScheduler,支持 Cron 表达式和特性标注 [Scheduler],可视化任务管理。

🔌 可插拔扩展

通过扩展项目按需添加能力:

扩展 功能
EasyAdminBlazor.Mail SMTP 邮件发送
EasyAdminBlazor.Captcha 表单验证码
EasyAdminBlazor.Redis Redis 缓存/消息持久化
EasyAdminBlazor.FusionCache 混合缓存加速
EasyAdminBlazor.Chat 实时聊天插件
EasyAdminBlazor.MultiTenant 多租户支持
EasyAdminBlazor.Scheduler 后台任务调度
EasyAdminBlazor.HtmlEditor TinyMCE 富文本编辑器
EasyAdminBlazor.WeChat 微信小程序、微信支付集成

🛡️ 安全特性

  • 密码 PBKDF2 加密存储
  • Cookie 认证 + AES 加密
  • CSRF 防护(Antiforgery Token)
  • 管理后台路由加密(AdminRouteSecret)
  • 操作日志审计
  • 登录失败次数限制 + 验证码

🏗️ 技术栈

层级 技术
框架 .NET 10
UI Blazor Server / BootstrapBlazor
ORM FreeSql(支持 MySQL、Sqlite、PostgreSQL、SQL Server 等)
实时通信 SignalR
认证 Cookie Authentication + ASP.NET Core Identity
缓存 IMemoryCache / Redis / FusionCache
任务调度 FreeScheduler
图片处理 SixLabors.ImageSharp
ID 生成 Yitter 雪花算法

🚀 快速开始

环境要求

  • .NET 10 SDK
  • MySQL 8.0+(或其他 FreeSql 支持的数据库)
  • (可选)Redis

第一步:创建项目

dotnet new web -n YourProjectName
cd YourProjectName

第二步:安装 NuGet 包

# 核心包(必须)
dotnet add package EasyAdminBlazor

# 数据库支持(根据你的数据库选择其中一个)
dotnet add package FreeSql.Provider.MySqlConnector      # MySQL
dotnet add package FreeSql.Provider.SqlServer  # SQL Server
dotnet add package FreeSql.Provider.Sqlite     # SQLite
dotnet add package FreeSql.Provider.PostgreSQL # PostgreSQL

第三步:配置 Program.cs

var builder = WebApplication.CreateBuilder(args);

var configuration = builder.Configuration;

builder.AddEasyAdminBlazor(new EasyAdminBlazorOptions
{
    EnableLoginCaptcha = true,
    EnableMessage   =true,
    ShowHelp =true,
    AesKey= "XME2k7nA9vJy9osiU389469Y",
    AdminRouteSecret= "i4ByMAX4",
    Assemblies = [typeof(Program).Assembly],
    FreeSqlBuilder = a => a
        .UseConnectionString(DataType.MySql, configuration["ConnectionStrings:default"])
        .UseMonitorCommand(cmd => System.Console.WriteLine($"[{DateTime.Now.ToString("HH:mm:ss")}] {cmd.CommandText}\r\n"))//监听SQL语句
        .UseAutoSyncStructure(true)
})
    .AddEasyAdminBlazorMail() // 添加smtp邮件扩展
    .AddEasyAdminBlazorTinyMCEEditor() // 编辑器扩展
    .AddEasyAdminBlazorRedis(configuration["Redis:ConnectionString"]!)
    .AddEasyAdminBlazorChat() // 聊天插件(依赖redis,没配置则不启用)
    .AddEasyAdminBlazorWeChat() // 微信插件
    .AddEasyAdminBlazorScheduler() // 计划任务扩展
    .AddEasyAdminBlazorFusionCache()
    .AddEasyAdminBlazorMultiTenant()
    .AddEasyAdminBlazorCaptcha(options =>
    {
        options.Chars = "0123456789";
    });  // 验证码

// Add services to the container.
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

// 注册 Session 服务
builder.Services.AddSession(options =>
{
    options.IdleTimeout = TimeSpan.FromMinutes(30);
    options.Cookie.HttpOnly = true;
    options.Cookie.IsEssential = true;
});

builder.Services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");

builder.Services.AddRazorComponents().AddInteractiveServerComponents();

builder.Services.AddBootstrapBlazorTableExportService();

builder.Services.Configure<HubOptions>(option => {
    option.MaximumReceiveMessageSize = null;
});

var app = builder.Build();

// 如果EnableLocalization=true,请取消注释以下
//var option = app.Services.GetService<IOptions<RequestLocalizationOptions>>();
//if (option != null)
//{
//    app.UseRequestLocalization(option.Value);
//}

app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.All });

app.UseStaticFiles();

app.UseAntiforgery();

app.MapRazorComponents<App>()
    .AddAdditionalAssemblies(typeof(EasyAdminBlazor._Imports).Assembly)
    .AddInteractiveServerRenderMode();

// 使用 Session
app.UseSession();

app.UseChat();
app.UseEasyAdminBlazor();

app.Run();

第四步:appsettings.json 完整配置示例

{
  "ConnectionStrings": {
    "Default": "Data Source=127.0.0.1;Port=3306;User ID=root;Password=123456; Initial Catalog=freesql_simple;Charset=utf8mb4; SslMode=none;Min pool size=1"
  },
  "Redis": {
    "ConnectionString": "127.0.0.1:6379,poolsize=10"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "FileSettings": {
    "DirectoryName": "uploads",
    "IncludeExtension": [ ".jpg", ".jpeg", ".png", ".gif", ".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".txt", ".webp" ],
    "ExcludeExtension": [ ".exe", ".dll", ".jar", ".php", ".aspx", ".bat", ".cmd", ".vbs", ".js", ".html", ".htm" ],
    "DateTimeDirectory": "yyyy/MM/dd",
    "KeepOriginalFile": false, //转换为webp后是否保留原文件
    "MaxImageWidth": 800,
    "WebpQuality": 80
  },
  "SmtpSettings": {
    "Server": "smtp.example.com",
    "Port": 587,
    "Username": "your_email@example.com",
    "Password": "your_email_password",
    "FromEmail": "your_email@example.com",
    "EnableSsl": true
  },
  "Wechat": {
    "App": {
      "AppKey": "your_app_key",
      "AppSecret": "your_app_secret"
    },
    "PayV3": {
      "AppId": "",
      "MchId": "",
      "ApiV3Key": "",
      "CertificatePath": "certs/apiclient_cert.pem",
      "KeyPath": "certs/apiclient_key.pem",
      "PubPath": "certs/pub_key.pem",
      "NotifyUrl": "",
      "BaseUrl": "https://api.mch.weixin.qq.com"
    }
  },
  "TinyMCE": {
    "ScriptSrc": "https://cdn.wang-zhan.cn/tinymce_8.3.2/tinymce.min.js"
  },
  "BootstrapBlazorOptions": {
    "ToastDelay": 4000,
    "MessageDelay": 4000,
    "SwalDelay": 4000,
    "EnableErrorLogger": true,
    "FallbackCulture": "en",
    "SupportedCultures": [
      "zh-CN",
      "en-US"
    ],
    "TableSettings": {
      "CheckboxColumnWidth": 36
    },
    "WebClientOptions": {
      "EnableIpLocator": true
    },
    "IgnoreLocalizerMissing": true,
    "StepSettings": {
      "Short": "1",
      "Int": "1",
      "Long": "1",
      "Float": "0.1",
      "Double": "0.01",
      "Decimal": "0.01"
    },
    "DefaultCultureInfo": "zh-CN"
  }
}

第五步:在根目录的Components文件夹下添加 App.razor 页面

<!DOCTYPE html>
<html lang="en" data-bs-theme='light'>

<head>
    <meta charset="utf-8" />
    <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="keywords" content="admin template,bootstrap,blazor,wasm,webassembly,UI,netcore,web,assembly">
    <meta name="description" content="基于Bootstrap和Freesql的后台系统,用于研发企业级中后台产品。">
    <meta name="author" content="gudufy (84383822@qq.com) www.wang-zhan.com.cn">
    <link rel="icon" href="favicon.ico" type="image/x-icon">
    <link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
    <link rel="apple-touch-icon" href="favicon.png"> 
    <base href="/" />
    <link rel="stylesheet" href="@Assets["_content/BootstrapBlazor.FontAwesome/css/font-awesome.min.css"]" />
    <link rel="stylesheet" href="@Assets["_content/BootstrapBlazor/css/bootstrap.blazor.bundle.min.css"]" />
    <link rel="stylesheet" href="@Assets["_content/EasyAdminBlazor/ant.css"]">
    <link rel="stylesheet" href="@Assets["_content/EasyAdminBlazor/adminblazor.css"]" />
    <link rel="stylesheet" href="@Assets["EasyAdminBlazor.styles.css"]" />
    <link rel="stylesheet" href="@Assets["EasyAdminBlazor.Test.styles.css"]" />
    <title>后台管理系统 - EasyAdminBlazor</title>
    <ImportMap></ImportMap>
    <HeadOutlet @rendermode="new InteractiveServerRenderMode(false)" />
</head>

<body>
    <Routes @rendermode="new InteractiveServerRenderMode(false)" />

    <ReconnectorOutlet ReconnectInterval="5000" @rendermode="new InteractiveServerRenderMode(false)" />

    <script Src="_content/BootstrapBlazor/js/bootstrap.blazor.bundle.min.js"></script>
    <script src="_framework/blazor.web.js"></script>
    <script src="@Assets["_content/EasyAdminBlazor/adminblazor.js"]"></script>
    <script Src="@Assets["_content/EasyAdminBlazor.HtmlEditor/TinyMCEEditor.razor.js"]"></script>
</body>

</html>

第六步:在根目录的Components文件夹下添加 Routes.razor 页面

<Router AppAssembly="@typeof(Program).Assembly" AdditionalAssemblies="new[] { typeof(MainLayout).Assembly }">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    </Found>
</Router>

第六步:运行项目

dotnet run

默认管理员账号:admin,密码:123yyq。租户默认密码根据租户编码自动生成(如 vip123)。