feat: 完成多租户saas框架搭建

This commit is contained in:
橙子
2024-01-21 18:11:04 +08:00
parent 68c1d59638
commit 2013aa5db8
19 changed files with 295 additions and 266 deletions

View File

@@ -1,168 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.MultiTenancy;
[Dependency(ReplaceServices = true)]
public class MultiTenantConnectionStringResolver2 : DefaultConnectionStringResolver
{
private readonly ICurrentTenant _currentTenant;
private readonly IServiceProvider _serviceProvider;
public MultiTenantConnectionStringResolver2(
IOptionsMonitor<AbpDbConnectionOptions> options,
ICurrentTenant currentTenant,
IServiceProvider serviceProvider)
: base(options)
{
_currentTenant = currentTenant;
_serviceProvider = serviceProvider;
}
public override async Task<string> ResolveAsync(string? connectionStringName = null)
{
if (_currentTenant.Id == null)
{
//No current tenant, fallback to default logic
return await base.ResolveAsync(connectionStringName);
}
var tenant = await FindTenantConfigurationAsync(_currentTenant.Id.Value);
if (tenant == null || tenant.ConnectionStrings.IsNullOrEmpty())
{
//Tenant has not defined any connection string, fallback to default logic
return await base.ResolveAsync(connectionStringName);
}
var tenantDefaultConnectionString = tenant.ConnectionStrings?.Default;
//Requesting default connection string...
if (connectionStringName == null ||
connectionStringName == ConnectionStrings.DefaultConnectionStringName)
{
//Return tenant's default or global default
return !tenantDefaultConnectionString.IsNullOrWhiteSpace()
? tenantDefaultConnectionString!
: Options.ConnectionStrings.Default!;
}
//Requesting specific connection string...
var connString = tenant.ConnectionStrings?.GetOrDefault(connectionStringName);
if (!connString.IsNullOrWhiteSpace())
{
//Found for the tenant
return connString!;
}
//Fallback to the mapped database for the specific connection string
var database = Options.Databases.GetMappedDatabaseOrNull(connectionStringName);
if (database != null && database.IsUsedByTenants)
{
connString = tenant.ConnectionStrings?.GetOrDefault(database.DatabaseName);
if (!connString.IsNullOrWhiteSpace())
{
//Found for the tenant
return connString!;
}
}
//Fallback to tenant's default connection string if available
if (!tenantDefaultConnectionString.IsNullOrWhiteSpace())
{
return tenantDefaultConnectionString!;
}
return await base.ResolveAsync(connectionStringName);
}
[Obsolete("Use ResolveAsync method.")]
public override string Resolve(string? connectionStringName = null)
{
if (_currentTenant.Id == null)
{
//No current tenant, fallback to default logic
return base.Resolve(connectionStringName);
}
var tenant = FindTenantConfiguration(_currentTenant.Id.Value);
if (tenant == null || tenant.ConnectionStrings.IsNullOrEmpty())
{
//Tenant has not defined any connection string, fallback to default logic
return base.Resolve(connectionStringName);
}
var tenantDefaultConnectionString = tenant.ConnectionStrings?.Default;
//Requesting default connection string...
if (connectionStringName == null ||
connectionStringName == ConnectionStrings.DefaultConnectionStringName)
{
//Return tenant's default or global default
return !tenantDefaultConnectionString.IsNullOrWhiteSpace()
? tenantDefaultConnectionString!
: Options.ConnectionStrings.Default!;
}
//Requesting specific connection string...
var connString = tenant.ConnectionStrings?.GetOrDefault(connectionStringName);
if (!connString.IsNullOrWhiteSpace())
{
//Found for the tenant
return connString!;
}
//Fallback to tenant's default connection string if available
if (!tenantDefaultConnectionString.IsNullOrWhiteSpace())
{
return tenantDefaultConnectionString!;
}
//Try to find the specific connection string for given name
var connStringInOptions = Options.ConnectionStrings.GetOrDefault(connectionStringName);
if (!connStringInOptions.IsNullOrWhiteSpace())
{
return connStringInOptions!;
}
//Fallback to the global default connection string
var defaultConnectionString = Options.ConnectionStrings.Default;
if (!defaultConnectionString.IsNullOrWhiteSpace())
{
return defaultConnectionString!;
}
throw new AbpException("No connection string defined!");
}
protected virtual async Task<TenantConfiguration?> FindTenantConfigurationAsync(Guid tenantId)
{
using (var serviceScope = _serviceProvider.CreateScope())
{
var tenantStore = serviceScope
.ServiceProvider
.GetRequiredService<ITenantStore>();
return await tenantStore.FindAsync(tenantId);
}
}
[Obsolete("Use FindTenantConfigurationAsync method.")]
protected virtual TenantConfiguration? FindTenantConfiguration(Guid tenantId)
{
using (var serviceScope = _serviceProvider.CreateScope())
{
var tenantStore = serviceScope
.ServiceProvider
.GetRequiredService<ITenantStore>();
return tenantStore.Find(tenantId);
}
}
}

View File

@@ -1,8 +1,5 @@
using Microsoft.Extensions.DependencyInjection.Extensions;
using Serilog;
using Serilog.Events;
using Volo.Abp.Data;
using Volo.Abp.MultiTenancy;
using Yi.Abp.Web;
//创建日志,可使用{SourceContext}记录
@@ -26,7 +23,6 @@ try
builder.Host.UseAutofac();
builder.Host.UseSerilog();
await builder.Services.AddApplicationAsync<YiAbpWebModule>();
builder.Services.Replace(new ServiceDescriptor(typeof(IConnectionStringResolver), typeof(MultiTenantConnectionStringResolver2), ServiceLifetime.Transient));
var app = builder.Build();
await app.InitializeApplicationAsync();
await app.RunAsync();

View File

@@ -1,5 +1,4 @@
using System.Text;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Cors;
using Microsoft.IdentityModel.Tokens;
@@ -14,6 +13,7 @@ using Volo.Abp.AspNetCore.Serilog;
using Volo.Abp.Auditing;
using Volo.Abp.Autofac;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Swashbuckle;
using Yi.Abp.Application;
using Yi.Abp.SqlsugarCore;
@@ -107,6 +107,12 @@ namespace Yi.Abp.Web
});
});
//配置多租户
Configure<AbpTenantResolveOptions>(options =>
{
//基于cookie jwt不好用有坑
options.TenantResolvers.RemoveAll(x => x.Name == CookieTenantResolveContributor.ContributorName);
});
//jwt鉴权
var jwtOptions = configuration.GetSection(nameof(JwtOptions)).Get<JwtOptions>();