Skip to content

Commit 4485fdc

Browse files
committed
feat(tenant): 完整多租户数据隔离 - BaseEntity统一TenantId + DbContext全局过滤器 + 所有Controllers写入TenantId + SQLite补列
1 parent b5b01bc commit 4485fdc

17 files changed

Lines changed: 208 additions & 18 deletions

Juggle.Api/Controllers/Api/DataSourceController.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Juggle.Application.Models.Request;
22
using Juggle.Application.Models.Response;
3+
using Juggle.Application.Services;
34
using Juggle.Application.Services.Impl;
45
using Juggle.Domain.Entities;
56
using Juggle.Infrastructure.Persistence;
@@ -16,11 +17,13 @@ public class DataSourceController : ControllerBase
1617
{
1718
private readonly JuggleDbContext _db;
1819
private readonly DataSourceService _dsService;
20+
private readonly ITenantAccessor _tenant;
1921

20-
public DataSourceController(JuggleDbContext db, DataSourceService dsService)
22+
public DataSourceController(JuggleDbContext db, DataSourceService dsService, ITenantAccessor tenant)
2123
{
2224
_db = db;
2325
_dsService = dsService;
26+
_tenant = tenant;
2427
}
2528

2629
[HttpPost("add")]
@@ -35,6 +38,7 @@ public async Task<ApiResult> Add([FromBody] DataSourceAddRequest req)
3538
DbName = req.DbName,
3639
Username = req.Username,
3740
Password = req.Password,
41+
TenantId = _tenant.TenantId,
3842
CreatedAt = DateTime.Now.ToString("o")
3943
};
4044
_db.DataSources.Add(entity);

Juggle.Api/Controllers/Api/FlowDefinitionController.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Text.Json;
22
using Juggle.Application.Models.Request;
33
using Juggle.Application.Models.Response;
4+
using Juggle.Application.Services;
45
using Juggle.Application.Services.Flow;
56
using Juggle.Domain.Entities;
67
using Juggle.Infrastructure.Persistence;
@@ -17,11 +18,13 @@ public class FlowDefinitionController : ControllerBase
1718
{
1819
private readonly JuggleDbContext _db;
1920
private readonly FlowExecutionService _flowExec;
21+
private readonly ITenantAccessor _tenant;
2022

21-
public FlowDefinitionController(JuggleDbContext db, FlowExecutionService flowExec)
23+
public FlowDefinitionController(JuggleDbContext db, FlowExecutionService flowExec, ITenantAccessor tenant)
2224
{
2325
_db = db;
2426
_flowExec = flowExec;
27+
_tenant = tenant;
2528
}
2629

2730
[HttpPost("add")]
@@ -37,6 +40,7 @@ public async Task<ApiResult> Add([FromBody] FlowDefinitionAddRequest req)
3740
GroupName = req.GroupName,
3841
FlowContent = "[]",
3942
Status = 0,
43+
TenantId = _tenant.TenantId,
4044
CreatedAt = DateTime.Now.ToString("o")
4145
};
4246
_db.FlowDefinitions.Add(entity);
@@ -258,6 +262,7 @@ public async Task<ApiResult> Import([FromBody] System.Text.Json.JsonElement body
258262
FlowType = flowType,
259263
FlowContent = flowContent,
260264
Status = 0,
265+
TenantId = _tenant.TenantId,
261266
CreatedAt = DateTime.Now.ToString("o")
262267
};
263268
_db.FlowDefinitions.Add(entity);
@@ -320,6 +325,7 @@ public async Task<ApiResult> Clone(long id)
320325
GroupName = source.GroupName,
321326
FlowContent = source.FlowContent,
322327
Status = 0,
328+
TenantId = _tenant.TenantId,
323329
CreatedAt = DateTime.Now.ToString("o")
324330
};
325331
_db.FlowDefinitions.Add(cloned);
@@ -394,6 +400,7 @@ public async Task<ApiResult> Deploy([FromBody] FlowDeployRequest req)
394400
FlowDesc = definition.FlowDesc,
395401
FlowType = definition.FlowType,
396402
Status = 1,
403+
TenantId = _tenant.TenantId,
397404
CreatedAt = DateTime.Now.ToString("o")
398405
};
399406
_db.FlowInfos.Add(flowInfo);
@@ -419,6 +426,7 @@ public async Task<ApiResult> Deploy([FromBody] FlowDeployRequest req)
419426
Version = newVersion,
420427
FlowContent = definition.FlowContent,
421428
Status = 1,
429+
TenantId = _tenant.TenantId,
422430
CreatedAt = DateTime.Now.ToString("o")
423431
};
424432
_db.FlowVersions.Add(flowVersion);

Juggle.Api/Controllers/Api/ObjectController.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Juggle.Infrastructure.Persistence;
33
using Juggle.Application.Models.Request;
44
using Juggle.Application.Models.Response;
5+
using Juggle.Application.Services;
56
using Microsoft.AspNetCore.Authorization;
67
using Microsoft.AspNetCore.Mvc;
78
using Microsoft.EntityFrameworkCore;
@@ -14,8 +15,13 @@ namespace Juggle.Api.Controllers.Api;
1415
public class ObjectController : ControllerBase
1516
{
1617
private readonly JuggleDbContext _db;
18+
private readonly ITenantAccessor _tenant;
1719

18-
public ObjectController(JuggleDbContext db) => _db = db;
20+
public ObjectController(JuggleDbContext db, ITenantAccessor tenant)
21+
{
22+
_db = db;
23+
_tenant = tenant;
24+
}
1925

2026
[HttpPost("add")]
2127
public async Task<ApiResult> Add([FromBody] ObjectAddRequest req)
@@ -26,6 +32,7 @@ public async Task<ApiResult> Add([FromBody] ObjectAddRequest req)
2632
ObjectCode = code,
2733
ObjectName = req.ObjectName,
2834
ObjectDesc = req.ObjectDesc,
35+
TenantId = _tenant.TenantId,
2936
CreatedAt = DateTime.Now.ToString("o")
3037
};
3138
_db.Objects.Add(entity);

Juggle.Api/Controllers/Api/ScheduleTaskController.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Juggle.Application.Models.Request;
22
using Juggle.Application.Models.Response;
33
using Juggle.Api.Services;
4+
using Juggle.Application.Services;
45
using Juggle.Domain.Entities;
56
using Juggle.Infrastructure.Persistence;
67
using Microsoft.AspNetCore.Authorization;
@@ -15,10 +16,12 @@ namespace Juggle.Api.Controllers.Api;
1516
public class ScheduleTaskController : ControllerBase
1617
{
1718
private readonly JuggleDbContext _db;
19+
private readonly ITenantAccessor _tenant;
1820

19-
public ScheduleTaskController(JuggleDbContext db)
21+
public ScheduleTaskController(JuggleDbContext db, ITenantAccessor tenant)
2022
{
2123
_db = db;
24+
_tenant = tenant;
2225
}
2326

2427
[HttpPost("add")]
@@ -36,6 +39,7 @@ public async Task<ApiResult> Add([FromBody] ScheduleTaskAddRequest req)
3639
CronExpression = req.CronExpression,
3740
InputJson = req.InputJson,
3841
Status = 1,
42+
TenantId = _tenant.TenantId,
3943
NextRunTime = ScheduleTaskService.CalculateNextRun(req.CronExpression, DateTime.Now),
4044
CreatedAt = DateTime.Now.ToString("o")
4145
};

Juggle.Api/Controllers/Api/StaticVariableController.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Juggle.Infrastructure.Persistence;
33
using Juggle.Application.Models.Request;
44
using Juggle.Application.Models.Response;
5+
using Juggle.Application.Services;
56
using Microsoft.AspNetCore.Authorization;
67
using Microsoft.AspNetCore.Mvc;
78
using Microsoft.EntityFrameworkCore;
@@ -15,7 +16,12 @@ namespace Juggle.Api.Controllers.Api;
1516
public class StaticVariableController : ControllerBase
1617
{
1718
private readonly JuggleDbContext _db;
18-
public StaticVariableController(JuggleDbContext db) => _db = db;
19+
private readonly ITenantAccessor _tenant;
20+
public StaticVariableController(JuggleDbContext db, ITenantAccessor tenant)
21+
{
22+
_db = db;
23+
_tenant = tenant;
24+
}
1925

2026
[HttpGet("list")]
2127
public async Task<ApiResult> List([FromQuery] string? groupName)
@@ -42,6 +48,7 @@ public async Task<ApiResult> Add([FromBody] StaticVarSaveRequest req)
4248
DefaultValue = req.DefaultValue,
4349
Description = req.Description,
4450
GroupName = req.GroupName,
51+
TenantId = _tenant.TenantId,
4552
CreatedAt = DateTime.Now.ToString("o")
4653
};
4754
_db.StaticVariables.Add(entity);

Juggle.Api/Controllers/Api/SuiteController.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Juggle.Infrastructure.Persistence;
33
using Juggle.Application.Models.Request;
44
using Juggle.Application.Models.Response;
5+
using Juggle.Application.Services;
56
using Microsoft.AspNetCore.Authorization;
67
using Microsoft.AspNetCore.Mvc;
78
using Microsoft.EntityFrameworkCore;
@@ -14,8 +15,13 @@ namespace Juggle.Api.Controllers.Api;
1415
public class SuiteController : ControllerBase
1516
{
1617
private readonly JuggleDbContext _db;
18+
private readonly ITenantAccessor _tenant;
1719

18-
public SuiteController(JuggleDbContext db) => _db = db;
20+
public SuiteController(JuggleDbContext db, ITenantAccessor tenant)
21+
{
22+
_db = db;
23+
_tenant = tenant;
24+
}
1925

2026
[HttpPost("add")]
2127
public async Task<ApiResult> Add([FromBody] SuiteAddRequest req)
@@ -29,6 +35,7 @@ public async Task<ApiResult> Add([FromBody] SuiteAddRequest req)
2935
SuiteImage = req.SuiteImage,
3036
SuiteVersion = req.SuiteVersion,
3137
SuiteFlag = 0,
38+
TenantId = _tenant.TenantId,
3239
CreatedAt = DateTime.Now.ToString("o")
3340
};
3441
_db.Suites.Add(entity);
@@ -161,6 +168,7 @@ public async Task<ApiResult> Import([FromBody] System.Text.Json.JsonElement body
161168
SuiteVersion = suiteVersion,
162169
SuiteImage = suiteImage,
163170
SuiteFlag = 0,
171+
TenantId = _tenant.TenantId,
164172
CreatedAt = DateTime.Now.ToString("o")
165173
};
166174
_db.Suites.Add(entity);

Juggle.Api/Controllers/Api/TokenController.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Juggle.Infrastructure.Persistence;
33
using Juggle.Application.Models.Request;
44
using Juggle.Application.Models.Response;
5+
using Juggle.Application.Services;
56
using Microsoft.AspNetCore.Authorization;
67
using Microsoft.AspNetCore.Mvc;
78
using Microsoft.EntityFrameworkCore;
@@ -14,8 +15,13 @@ namespace Juggle.Api.Controllers.Api;
1415
public class TokenController : ControllerBase
1516
{
1617
private readonly JuggleDbContext _db;
18+
private readonly ITenantAccessor _tenant;
1719

18-
public TokenController(JuggleDbContext db) => _db = db;
20+
public TokenController(JuggleDbContext db, ITenantAccessor tenant)
21+
{
22+
_db = db;
23+
_tenant = tenant;
24+
}
1925

2026
[HttpPost("add")]
2127
public async Task<ApiResult> Add([FromBody] TokenAddRequest req)
@@ -27,6 +33,7 @@ public async Task<ApiResult> Add([FromBody] TokenAddRequest req)
2733
TokenName = req.TokenName,
2834
ExpiredAt = req.ExpiredAt,
2935
Status = 1,
36+
TenantId = _tenant.TenantId,
3037
CreatedAt = DateTime.Now.ToString("o")
3138
};
3239
_db.Tokens.Add(entity);
@@ -96,6 +103,7 @@ public async Task<ApiResult> SavePermissions(long tokenId, [FromBody] List<Token
96103
PermissionType = perm.PermissionType,
97104
ResourceKey = perm.ResourceKey,
98105
ResourceName = perm.ResourceName,
106+
TenantId = _tenant.TenantId,
99107
CreatedAt = DateTime.Now.ToString("o")
100108
});
101109
}

Juggle.Api/Controllers/Api/WebhookController.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using Juggle.Application.Models.Response;
2+
using Juggle.Application.Services;
23
using Juggle.Domain.Entities;
34
using Juggle.Infrastructure.Persistence;
5+
using Microsoft.AspNetCore.Authorization;
46
using Microsoft.AspNetCore.Mvc;
57
using Microsoft.EntityFrameworkCore;
68

@@ -9,13 +11,16 @@ namespace Juggle.Api.Controllers.Api;
911
/// <summary>Webhook 管理接口</summary>
1012
[ApiController]
1113
[Route("api/system/webhook")]
14+
[Authorize]
1215
public class WebhookController : ControllerBase
1316
{
1417
private readonly JuggleDbContext _db;
18+
private readonly ITenantAccessor _tenant;
1519

16-
public WebhookController(JuggleDbContext db)
20+
public WebhookController(JuggleDbContext db, ITenantAccessor tenant)
1721
{
1822
_db = db;
23+
_tenant = tenant;
1924
}
2025

2126
/// <summary>分页查询 Webhook 列表</summary>
@@ -75,6 +80,7 @@ public async Task<ApiResult> Save([FromBody] WebhookEntity webhook)
7580
var def = await _db.FlowDefinitions.FirstOrDefaultAsync(d => d.FlowKey == webhook.FlowKey && d.Deleted == 0);
7681
if (def != null) webhook.FlowName = def.FlowName;
7782

83+
webhook.TenantId = _tenant.TenantId;
7884
webhook.CreatedAt = DateTime.Now.ToString("o");
7985
webhook.TriggerCount = 0;
8086
_db.Webhooks.Add(webhook);

Juggle.Api/Program.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,21 @@ static string MaskPassword(string connStr)
9393
);
9494
}
9595

96-
builder.Services.AddDbContext<JuggleDbContext>(ConfigureDbContext);
96+
// 注册 IHttpContextAccessor(DbContext 内部读取当前 HTTP 请求的租户信息)
97+
builder.Services.AddHttpContextAccessor();
98+
99+
// 注册 ICurrentTenantProvider:从 JWT Claims 动态获取当前租户 ID
100+
builder.Services.AddScoped<Juggle.Infrastructure.Persistence.ICurrentTenantProvider,
101+
Juggle.Api.Services.HttpContextTenantProvider>();
102+
103+
// 注册 DbContext:EF Core DI 会自动注入 ICurrentTenantProvider(因为它已注册为 Scoped)
104+
builder.Services.AddDbContext<JuggleDbContext>((sp, opts) =>
105+
{
106+
ConfigureDbContext(opts);
107+
});
108+
// 说明:JuggleDbContext 有两个构造函数:
109+
// (DbContextOptions) → 用于 EnsureCreated / 测试
110+
// (DbContextOptions, ICurrentTenantProvider) → 用于 HTTP 请求(EF Core DI 自动选择参数最多的)
97111

98112
// 如果不是 SQLite,则需要在启动时确保数据库已迁移
99113
// SQLite 使用 EnsureCreated,其他数据库使用 Migrate 或 EnsureCreated
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using Juggle.Infrastructure.Persistence;
2+
3+
namespace Juggle.Api.Services;
4+
5+
/// <summary>
6+
/// 从当前 HTTP 请求的 JWT Claims 中获取租户 ID。
7+
/// 超级管理员(RoleId=1)返回 null,DbContext 不加过滤。
8+
/// </summary>
9+
public class HttpContextTenantProvider : ICurrentTenantProvider
10+
{
11+
private readonly IHttpContextAccessor _httpContextAccessor;
12+
13+
public HttpContextTenantProvider(IHttpContextAccessor httpContextAccessor)
14+
{
15+
_httpContextAccessor = httpContextAccessor;
16+
}
17+
18+
public long? GetCurrentTenantId()
19+
{
20+
var user = _httpContextAccessor.HttpContext?.User;
21+
if (user == null || user.Identity?.IsAuthenticated != true)
22+
return null;
23+
24+
// 超级管理员(RoleId=1)不受租户过滤,可看所有数据
25+
var roleClaim = user.FindFirst("RoleId")?.Value;
26+
if (roleClaim == "1") return null;
27+
28+
var tenantClaim = user.FindFirst("TenantId")?.Value;
29+
return long.TryParse(tenantClaim, out var tid) ? tid : null;
30+
}
31+
}

0 commit comments

Comments
 (0)