Browse Source

fix(saas): 修复新建租户时的连接字符串校验

pull/994/head
colin 1 year ago
parent
commit
15e571a823
  1. 49
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application/LINGYUN/Abp/Saas/Tenants/TenantAppService.cs
  2. 12
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/AbpSaasErrorCodes.cs
  3. 4
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/en.json
  4. 4
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/zh-Hans.json
  5. 14
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Features/SaasFeatureDefinitionProvider.cs

49
aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application/LINGYUN/Abp/Saas/Tenants/TenantAppService.cs

@ -1,5 +1,6 @@
using LINGYUN.Abp.Saas.Features;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
@ -8,7 +9,6 @@ using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Data;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Features;
using Volo.Abp.MultiTenancy;
using Volo.Abp.ObjectExtending;
@ -20,15 +20,18 @@ public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService
protected IDistributedEventBus EventBus { get; }
protected ITenantRepository TenantRepository { get; }
protected ITenantManager TenantManager { get; }
protected IConnectionStringChecker ConnectionStringChecker { get; }
public TenantAppService(
ITenantRepository tenantRepository,
ITenantManager tenantManager,
IDistributedEventBus eventBus)
IDistributedEventBus eventBus,
IConnectionStringChecker connectionStringChecker)
{
EventBus = eventBus;
TenantRepository = tenantRepository;
TenantManager = tenantManager;
ConnectionStringChecker = connectionStringChecker;
}
public async virtual Task<TenantDto> GetAsync(Guid id)
@ -80,6 +83,7 @@ public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService
if (!input.UseSharedDatabase && !input.DefaultConnectionString.IsNullOrWhiteSpace())
{
await CheckConnectionString(input.DefaultConnectionString);
tenant.SetDefaultConnectionString(input.DefaultConnectionString);
}
@ -87,6 +91,7 @@ public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService
{
foreach (var connectionString in input.ConnectionStrings)
{
await CheckConnectionString(connectionString.Value, connectionString.Key);
tenant.SetConnectionString(connectionString.Key, connectionString.Value);
}
}
@ -119,6 +124,7 @@ public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService
await EventBus.PublishAsync(eto);
});
await CurrentUnitOfWork.SaveChangesAsync();
return ObjectMapper.Map<Tenant, TenantDto>(tenant);
@ -157,12 +163,17 @@ public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService
}
// 租户删除时查询会失效, 在删除前确认
var strategy = await FeatureChecker.GetAsync(SaasFeatureNames.Tenant.RecycleStrategy, RecycleStrategy.Recycle);
var recycleStrategy = RecycleStrategy.Recycle;
var strategySet = await FeatureChecker.GetOrNullAsync(SaasFeatureNames.Tenant.RecycleStrategy);
if (!strategySet.IsNullOrWhiteSpace() && Enum.TryParse<RecycleStrategy>(strategySet, out var strategy))
{
recycleStrategy = strategy;
}
var eto = new TenantDeletedEto
{
Id = tenant.Id,
Name = tenant.Name,
Strategy = strategy,
Strategy = recycleStrategy,
EntityVersion = tenant.EntityVersion,
DefaultConnectionString = tenant.FindDefaultConnectionString(),
};
@ -259,4 +270,34 @@ public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService
await CurrentUnitOfWork.SaveChangesAsync();
}
protected async virtual Task CheckConnectionString(string connectionString, string name = null)
{
try
{
var checkResult = await ConnectionStringChecker.CheckAsync(connectionString);
// 检查连接是否可用
if (!checkResult.Connected)
{
throw name.IsNullOrWhiteSpace()
? new BusinessException(AbpSaasErrorCodes.InvalidDefaultConnectionString)
: new BusinessException(AbpSaasErrorCodes.InvalidConnectionString)
.WithData("Name", name);
}
// 默认连接字符串改变不能影响到现有数据库
if (checkResult.DatabaseExists && name.IsNullOrWhiteSpace())
{
throw new BusinessException(AbpSaasErrorCodes.DefaultConnectionStringDatabaseExists);
}
}
catch (Exception e)
{
Logger.LogWarning("An error occurred while checking the validity of the connection string");
Logger.LogWarning(e.Message);
throw name.IsNullOrWhiteSpace()
? new BusinessException(AbpSaasErrorCodes.InvalidDefaultConnectionString)
: new BusinessException(AbpSaasErrorCodes.InvalidConnectionString)
.WithData("Name", name);
}
}
}

12
aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/AbpSaasErrorCodes.cs

@ -7,4 +7,16 @@ public static class AbpSaasErrorCodes
public const string DuplicateEditionDisplayName = Namespace + ":010001";
public const string DeleteUsedEdition = Namespace + ":010002";
public const string DuplicateTenantName = Namespace + ":020001";
/// <summary>
/// 无效的默认连接字符串
/// </summary>
public const string InvalidDefaultConnectionString = Namespace + ":020101";
/// <summary>
/// 默认连接字符串指向的数据库已经存在
/// </summary>
public const string DefaultConnectionStringDatabaseExists = Namespace + ":020102";
/// <summary>
/// {Name} 的连接字符串无效
/// </summary>
public const string InvalidConnectionString = Namespace + ":020103";
}

4
aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/en.json

@ -4,7 +4,9 @@
"Saas:010001": "Unable to create duplicate editions {DisplayName}!",
"Saas:010002": "Tried to delete the edition in use: {DisplayName}!",
"Saas:020001": "Unable to create duplicate tenants {Name}!",
"Saas:020002": "The database string that cannot be connected!",
"Saas:020101": "The default connection string cannot open a connection to the database!",
"Saas:020102": "The database pointed to by the default connection string already exists!",
"Saas:020103": "Unable to open the database connection pointed to by {Name}!",
"Volo.AbpIo.MultiTenancy:010001": "The tenant is unavailable or restricted!",
"Volo.AbpIo.MultiTenancy:010002": "Tenant unavailable!",
"Menu:Saas": "Saas",

4
aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/zh-Hans.json

@ -4,7 +4,9 @@
"Saas:010001": "已经存在名为 {DisplayName} 的版本!",
"Saas:010002": "试图删除正在使用的版本: {DisplayName}!",
"Saas:020001": "已经存在名为 {Name} 的租户!",
"Saas:020002": "无法连接的数据库字符串!",
"Saas:020101": "无法打开默认连接字符串指向的数据库连接!",
"Saas:020102": "默认连接字符串指向的数据库已经存在!",
"Saas:020103": "无法打开 {Name} 指向的数据库连接!",
"Volo.AbpIo.MultiTenancy:010001": "租户不可用或受限制!",
"Volo.AbpIo.MultiTenancy:010002": "租户不可用!",
"Menu:Saas": "Saas",

14
aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Features/SaasFeatureDefinitionProvider.cs

@ -18,22 +18,22 @@ public class SaasFeatureDefinitionProvider : FeatureDefinitionProvider
ItemSource = new StaticSelectionStringValueItemSource(
new LocalizableSelectionStringValueItem
{
Value = RecycleStrategy.Reserve.ToString(),
Value = "0",
DisplayText = new LocalizableStringInfo(
LocalizationResourceNameAttribute.GetName(typeof(AbpSaasResource)),
"RecycleStrategy:Reserve")
LocalizationResourceNameAttribute.GetName(typeof(AbpSaasResource)),
"RecycleStrategy:Reserve")
},
new LocalizableSelectionStringValueItem
{
Value = RecycleStrategy.Recycle.ToString(),
Value = "1",
DisplayText = new LocalizableStringInfo(
LocalizationResourceNameAttribute.GetName(typeof(AbpSaasResource)),
"RecycleStrategy:Recycle")
LocalizationResourceNameAttribute.GetName(typeof(AbpSaasResource)),
"RecycleStrategy:Recycle")
})
};
saas.AddFeature(
name: SaasFeatureNames.Tenant.RecycleStrategy,
defaultValue: RecycleStrategy.Recycle.ToString(),
defaultValue: "1",
displayName: L("Features:RecycleStrategy"),
description: L("Features:RecycleStrategyDesc"),
valueType: selectionValueType,

Loading…
Cancel
Save