commit 619518e7bfdfeea86f39ba5a63f233a7800e965f
Author: xiaolipro <2357729423@qq.com>
Date: Fri Mar 20 15:15:43 2026 +0800
init
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..783d1c5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,13 @@
+bin/
+obj/
+/packages/
+riderModule.iml
+/_ReSharper.Caches/
+
+.idea/
+/.vs
+/Fake.sln.DotSettings.user
+
+Logs/
+
+node_modules/
\ No newline at end of file
diff --git a/NuGet.Config b/NuGet.Config
new file mode 100644
index 0000000..69486f2
--- /dev/null
+++ b/NuGet.Config
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..8af4aa8
--- /dev/null
+++ b/README.md
@@ -0,0 +1,180 @@
+# SimpleAdmin API
+
+基于 Fake 框架的简单管理系统后端 API。
+
+## 技术栈
+
+- **.NET 8.0** - 最新的 .NET 平台
+- **Fake Framework** - 模块化应用框架
+- **Entity Framework Core** - ORM 框架
+- **SQL Server** - 数据库
+- **JWT** - 身份认证
+- **Swagger** - API 文档
+
+## 功能特性
+
+- ✅ 模块化架构
+- ✅ 自动 API 生成(ApplicationService 自动转换为 Controller)
+- ✅ RBAC 权限管理
+- ✅ JWT 认证
+- ✅ Swagger 文档
+- ✅ 依赖注入
+- ✅ 工作单元
+- ✅ 审计日志
+
+## 开始使用
+
+### 前置要求
+
+- .NET 8.0 SDK
+- SQL Server (LocalDB 或完整版)
+
+### 配置数据库
+
+修改 `appsettings.json` 中的连接字符串:
+
+```json
+{
+ "ConnectionStrings": {
+ "Default": "Server=(localdb)\\mssqllocaldb;Database=SimpleAdminDb;Trusted_Connection=true;MultipleActiveResultSets=true"
+ }
+}
+```
+
+### 数据库迁移
+
+```bash
+# 添加迁移
+dotnet ef migrations add InitialCreate --project ../modules/rbac/Fake.Rbac.Infrastructure
+
+# 更新数据库
+dotnet ef database update --project ../modules/rbac/Fake.Rbac.Infrastructure
+```
+
+### 运行项目
+
+```bash
+dotnet run
+```
+
+访问 http://localhost:5000 查看 Swagger 文档。
+
+## 默认账号
+
+系统会自动创建默认管理员账号:
+
+- 账号:admin
+- 密码:123456
+- 角色:超级管理员
+
+**⚠️ 重要:请在生产环境中立即修改默认密码!**
+
+## API 端点
+
+### 认证 API
+
+- `POST /api/auth/login` - 用户登录
+- `GET /api/auth/current` - 获取当前用户信息
+- `PUT /api/auth/password` - 修改密码
+
+### 用户管理 API
+
+- `GET /api/rbac/user/list` - 获取用户列表
+- `GET /api/rbac/user/{id}` - 获取用户详情
+- `POST /api/rbac/user` - 创建用户
+- `PUT /api/rbac/user/{id}` - 更新用户
+- `DELETE /api/rbac/user/{id}` - 删除用户
+- `PUT /api/rbac/user/{id}/roles` - 分配角色
+- `GET /api/rbac/user/{id}/permissions` - 获取用户权限
+
+### 角色管理 API
+
+- `GET /api/rbac/role/list` - 获取角色列表
+- `GET /api/rbac/role/all` - 获取所有角色
+- `GET /api/rbac/role/{id}` - 获取角色详情
+- `POST /api/rbac/role` - 创建角色
+- `PUT /api/rbac/role/{id}` - 更新角色
+- `DELETE /api/rbac/role/{id}` - 删除角色
+- `PUT /api/rbac/role/{id}/permissions` - 分配权限
+
+### 菜单管理 API
+
+- `GET /api/rbac/menu/tree` - 获取菜单树
+- `GET /api/rbac/menu/user/{userId}` - 获取用户菜单
+- `GET /api/rbac/menu/{id}` - 获取菜单详情
+- `POST /api/rbac/menu` - 创建菜单
+- `PUT /api/rbac/menu/{id}` - 更新菜单
+- `DELETE /api/rbac/menu/{id}` - 删除菜单
+
+### 权限管理 API
+
+- `GET /api/rbac/permission/all` - 获取所有权限
+- `GET /api/rbac/permission/tree` - 获取权限树
+
+## 项目结构
+
+```
+SimpleAdmin.Api/
+├── Controllers/ # 控制器(手动创建的)
+├── Program.cs # 程序入口
+├── SimpleAdminApiModule.cs # 主模块配置
+├── appsettings.json # 配置文件
+└── README.md
+```
+
+## Fake 框架特性
+
+### 自动 API 生成
+
+所有继承自 `ApplicationService` 的服务会自动生成对应的 API 端点,无需手动创建 Controller。
+
+### 模块化
+
+通过 `[DependsOn]` 特性声明模块依赖:
+
+```csharp
+[DependsOn(
+ typeof(FakeAspNetCoreModule),
+ typeof(FakeRbacApplicationModule)
+)]
+public class SimpleAdminApiModule : FakeModule
+{
+ // ...
+}
+```
+
+### 依赖注入
+
+框架自动注册服务,支持:
+- `ITransientDependency` - 瞬时
+- `IScopedDependency` - 作用域
+- `ISingletonDependency` - 单例
+
+### 工作单元
+
+应用服务方法自动包装在工作单元中,支持事务管理。
+
+## JWT 配置
+
+JWT 配置在 `appsettings.json` 中:
+
+```json
+{
+ "JwtSettings": {
+ "SecretKey": "your-secret-key-here",
+ "ExpiryInMinutes": 60
+ }
+}
+```
+
+## CORS 配置
+
+默认允许的前端地址:
+- http://localhost:3000
+- http://localhost:5173
+
+可在 `SimpleAdminApiModule.cs` 中修改。
+
+## 许可证
+
+MIT
diff --git a/SimpleAdmin.sln b/SimpleAdmin.sln
new file mode 100644
index 0000000..97bdf8b
--- /dev/null
+++ b/SimpleAdmin.sln
@@ -0,0 +1,44 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31903.59
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleAdmin.Api", "src\SimpleAdmin.Api.csproj", "{F6418A25-D1B2-48E1-BDCA-80CC5262BB18}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "items", "items", "{BE5132AD-C95E-4CB7-AFBD-0D4838AFD48C}"
+ ProjectSection(SolutionItems) = preProject
+ NuGet.Config = NuGet.Config
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {F6418A25-D1B2-48E1-BDCA-80CC5262BB18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F6418A25-D1B2-48E1-BDCA-80CC5262BB18}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F6418A25-D1B2-48E1-BDCA-80CC5262BB18}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {F6418A25-D1B2-48E1-BDCA-80CC5262BB18}.Debug|x64.Build.0 = Debug|Any CPU
+ {F6418A25-D1B2-48E1-BDCA-80CC5262BB18}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {F6418A25-D1B2-48E1-BDCA-80CC5262BB18}.Debug|x86.Build.0 = Debug|Any CPU
+ {F6418A25-D1B2-48E1-BDCA-80CC5262BB18}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F6418A25-D1B2-48E1-BDCA-80CC5262BB18}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F6418A25-D1B2-48E1-BDCA-80CC5262BB18}.Release|x64.ActiveCfg = Release|Any CPU
+ {F6418A25-D1B2-48E1-BDCA-80CC5262BB18}.Release|x64.Build.0 = Release|Any CPU
+ {F6418A25-D1B2-48E1-BDCA-80CC5262BB18}.Release|x86.ActiveCfg = Release|Any CPU
+ {F6418A25-D1B2-48E1-BDCA-80CC5262BB18}.Release|x86.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {F6418A25-D1B2-48E1-BDCA-80CC5262BB18} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
+ EndGlobalSection
+EndGlobal
diff --git a/src/Program.cs b/src/Program.cs
new file mode 100644
index 0000000..386aaa7
--- /dev/null
+++ b/src/Program.cs
@@ -0,0 +1,28 @@
+using Serilog;
+using SimpleAdmin.Api;
+
+var builder = WebApplication.CreateSlimBuilder(args);
+builder.Configuration.AddConsul("idwms/common", source => source.ReloadOnChange = true);
+builder.Configuration.AddConsul("idwms/admin", source => source.ReloadOnChange = true);
+
+Log.Logger = new LoggerConfiguration()
+ .ReadFrom.Configuration(builder.Configuration)
+ .CreateLogger();
+
+try
+{
+ builder.WebHost.UseUrls(builder.Configuration.GetSection("App:Urls").Get() ?? []);
+ builder.Host.UseAutofac().UseSerilog();
+ builder.Services.AddApplication();
+ var app = builder.Build();
+ app.InitializeApplication();
+ await app.RunAsync();
+}
+catch (Exception ex)
+{
+ Log.Fatal(ex, "G");
+}
+finally
+{
+ Log.CloseAndFlush();
+}
\ No newline at end of file
diff --git a/src/Properties/launchSettings.json b/src/Properties/launchSettings.json
new file mode 100644
index 0000000..786b6f7
--- /dev/null
+++ b/src/Properties/launchSettings.json
@@ -0,0 +1,34 @@
+{
+ "$schema": "http://json.schemastore.org/launchsettings.json",
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:22279",
+ "sslPort": 44353
+ }
+ },
+ "profiles": {
+ "dev": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "launchUrl": "",
+ "applicationUrl": "http://localhost:5281",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "staging": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": false,
+ "launchUrl": "",
+ "applicationUrl": "http://localhost:5281",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Staging",
+ "ASPNETCORE_PATHBASE": "/admin"
+ }
+ }
+ }
+}
diff --git a/src/SimpleAdmin.Api.csproj b/src/SimpleAdmin.Api.csproj
new file mode 100644
index 0000000..6169fe9
--- /dev/null
+++ b/src/SimpleAdmin.Api.csproj
@@ -0,0 +1,18 @@
+
+
+
+ net8.0
+ enable
+ enable
+ e3d506cf-f5ce-4ba5-bc8e-ab2c179f3034
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/SimpleAdmin.Api.http b/src/SimpleAdmin.Api.http
new file mode 100644
index 0000000..6da01ba
--- /dev/null
+++ b/src/SimpleAdmin.Api.http
@@ -0,0 +1,6 @@
+@SimpleAdmin.Api_HostAddress = http://localhost:5281
+
+GET {{SimpleAdmin.Api_HostAddress}}/weatherforecast/
+Accept: application/json
+
+###
diff --git a/src/SimpleAdminApiModule.cs b/src/SimpleAdminApiModule.cs
new file mode 100644
index 0000000..444199a
--- /dev/null
+++ b/src/SimpleAdminApiModule.cs
@@ -0,0 +1,89 @@
+using Fake.AspNetCore;
+using Fake.Autofac;
+using Fake.Modularity;
+using Fake.Rbac.Application;
+using Fake.Rbac.Infrastructure;
+using Fake.AspNetCore.Auditing;
+using Fake.AspNetCore.Mvc;
+using Fake.Serilog;
+using Microsoft.AspNetCore.HttpOverrides;
+
+namespace SimpleAdmin.Api;
+
+[DependsOn(
+ typeof(FakeAutofacModule),
+ typeof(FakeRbacApplicationModule),
+ typeof(FakeRbacInfrastructureModule),
+ typeof(FakeSerilogModule)
+)]
+public class SimpleAdminApiModule : FakeModule
+{
+ private const string DefaultCorsPolicyName = "default";
+
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ var services = context.Services;
+ var configuration = context.Services.GetConfiguration();
+
+ // 配置动态 API - 扫描 RBAC 应用服务
+ services.Configure(options =>
+ {
+ options.ApplicationServices2Controller(settings =>
+ {
+ settings.RootPath = "rbac";
+ });
+ });
+
+ services.AddFakeAspNetCoreAuditing();
+
+ // 添加 Fake Swagger 支持
+ services.AddFakeSwaggerGen(addSecurity: true);
+
+ services.AddCors(options =>
+ {
+ options.AddPolicy(DefaultCorsPolicyName, builder =>
+ {
+ builder.WithOrigins(configuration.GetSection("App:CorsOrigins").Get() ?? [])
+ .AllowAnyHeader()
+ .AllowAnyMethod()
+ .AllowCredentials();
+ });
+ });
+
+ services.Configure(options =>
+ {
+ options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
+ //新增如下两行
+ options.KnownNetworks.Clear();
+ options.KnownProxies.Clear();
+ });
+ }
+
+ public override void ConfigureApplication(ApplicationConfigureContext context)
+ {
+ var app = context.GetWebApplication();
+
+ // 虚拟路由-网关适配
+ app.UsePathBase(app.Configuration["ASPNETCORE_PATHBASE"]);
+
+ // Swagger
+ app.UseFakeSwagger();
+ // 异常处理
+ app.UseFakeExceptionHandling();
+ // CORS
+ app.UseCors("Default");
+
+ // 静态文件服务(用于头像等上传文件)
+ app.UseStaticFiles();
+
+ // 路由 - 必须在认证和授权之前
+ app.UseRouting();
+
+ // 认证和授权
+ app.UseAuthentication();
+ app.UseAuthorization();
+
+ // 端点映射
+ app.MapControllers();
+ }
+}
\ No newline at end of file
diff --git a/src/SimpleJwtService.cs b/src/SimpleJwtService.cs
new file mode 100644
index 0000000..0f2149f
--- /dev/null
+++ b/src/SimpleJwtService.cs
@@ -0,0 +1,28 @@
+using System.Security.Claims;
+using Fake.AspNetCore.Authentication;
+using Fake.DependencyInjection;
+using Fake.Rbac.Application.Jwt;
+using Fake.Rbac.Application.Services;
+using Fake.Rbac.Infrastructure;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Options;
+
+namespace SimpleAdmin.Api;
+
+///
+/// 自定义simple-admin auth jwt service
+///
+[Dependency(Replace = true)]
+public class SimpleJwtService(IOptions jwtOptions, IUserService userService, FakeRbacDbContext rbacDbContext)
+ : JwtService(jwtOptions, userService)
+{
+ public override async Task> GenerateClaimsByUserIdAsync(Guid userId,
+ CancellationToken cancellationToken)
+ {
+ var claims = await base.GenerateClaimsByUserIdAsync(userId, cancellationToken);
+ var mapId = await rbacDbContext.Database.SqlQuery($"select userid as value from user where id = {userId}")
+ .FirstAsync(cancellationToken);
+ claims.Add(new Claim("mapId", mapId.ToString()));
+ return claims;
+ }
+}
\ No newline at end of file
diff --git a/src/appsettings.Development.json b/src/appsettings.Development.json
new file mode 100644
index 0000000..62539e8
--- /dev/null
+++ b/src/appsettings.Development.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning",
+ "Microsoft.EntityFrameworkCore": "Information"
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/appsettings.json b/src/appsettings.json
new file mode 100644
index 0000000..01a9d8c
--- /dev/null
+++ b/src/appsettings.json
@@ -0,0 +1,8 @@
+{
+ "UseLocalConfigs": false,
+ "Consul": {
+ "Address": "https://consul.nanafa.com",
+ // 用户机密
+ "Token": ""
+ }
+}
\ No newline at end of file
diff --git a/src/uploads/avatars/08de4226-3fd4-4a5c-83e5-70e164b15f2f_20251224143133.jpg b/src/uploads/avatars/08de4226-3fd4-4a5c-83e5-70e164b15f2f_20251224143133.jpg
new file mode 100644
index 0000000..7525f91
Binary files /dev/null and b/src/uploads/avatars/08de4226-3fd4-4a5c-83e5-70e164b15f2f_20251224143133.jpg differ
diff --git a/src/uploads/avatars/08de4226-3fd4-4a5c-83e5-70e164b15f2f_20251225174451.jpg b/src/uploads/avatars/08de4226-3fd4-4a5c-83e5-70e164b15f2f_20251225174451.jpg
new file mode 100644
index 0000000..12e3f5c
Binary files /dev/null and b/src/uploads/avatars/08de4226-3fd4-4a5c-83e5-70e164b15f2f_20251225174451.jpg differ