63 changed files with 1502 additions and 307 deletions
@ -0,0 +1,21 @@ |
|||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.ExceptionHandling; |
||||
|
using Volo.Abp.Logging; |
||||
|
|
||||
|
namespace LINYUN.Abp.Aliyun |
||||
|
{ |
||||
|
public class AbpAliyunException : AbpException, IHasErrorCode, IHasLogLevel |
||||
|
{ |
||||
|
public LogLevel LogLevel { get; set; } |
||||
|
|
||||
|
public string Code { get; } |
||||
|
|
||||
|
public AbpAliyunException(string code, string message) |
||||
|
: base(message) |
||||
|
{ |
||||
|
Code = code; |
||||
|
LogLevel = LogLevel.Warning; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,21 +1,25 @@ |
|||||
using LINYUN.Abp.Aliyun.Localization; |
using LINYUN.Abp.Aliyun.Localization; |
||||
|
using Volo.Abp.Caching; |
||||
using Volo.Abp.Json; |
using Volo.Abp.Json; |
||||
using Volo.Abp.Localization; |
using Volo.Abp.Localization; |
||||
using Volo.Abp.Modularity; |
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.Settings; |
||||
using Volo.Abp.VirtualFileSystem; |
using Volo.Abp.VirtualFileSystem; |
||||
|
|
||||
namespace LINGYUN.Abp.Aliyun |
namespace LINGYUN.Abp.Aliyun |
||||
{ |
{ |
||||
[DependsOn( |
[DependsOn( |
||||
|
typeof(AbpCachingModule), |
||||
|
typeof(AbpSettingsModule), |
||||
typeof(AbpJsonModule), |
typeof(AbpJsonModule), |
||||
typeof(AbpLocalizationModule))] |
typeof(AbpLocalizationModule))] |
||||
public class AbpAliyunCloudModule : AbpModule |
public class AbpAliyunModule : AbpModule |
||||
{ |
{ |
||||
public override void ConfigureServices(ServiceConfigurationContext context) |
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
{ |
{ |
||||
Configure<AbpVirtualFileSystemOptions>(options => |
Configure<AbpVirtualFileSystemOptions>(options => |
||||
{ |
{ |
||||
options.FileSets.AddEmbedded<AbpAliyunCloudModule>(); |
options.FileSets.AddEmbedded<AbpAliyunModule>(); |
||||
}); |
}); |
||||
|
|
||||
Configure<AbpLocalizationOptions>(options => |
Configure<AbpLocalizationOptions>(options => |
||||
@ -0,0 +1,32 @@ |
|||||
|
using Aliyun.Acs.Core; |
||||
|
using Aliyun.Acs.Core.Auth; |
||||
|
using Aliyun.Acs.Core.Profile; |
||||
|
using Volo.Abp.Caching; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Settings; |
||||
|
|
||||
|
namespace LINYUN.Abp.Aliyun |
||||
|
{ |
||||
|
public class AcsClientFactory : AliyunClientFactory<IAcsClient>, IAcsClientFactory, ITransientDependency |
||||
|
{ |
||||
|
public AcsClientFactory( |
||||
|
ISettingProvider settingProvider, |
||||
|
IDistributedCache<AliyunBasicSessionCredentialsCacheItem> cache) |
||||
|
: base(settingProvider, cache) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
protected override IAcsClient GetClient(string regionId, string accessKeyId, string accessKeySecret) |
||||
|
{ |
||||
|
return new DefaultAcsClient( |
||||
|
DefaultProfile.GetProfile(regionId, accessKeyId, accessKeySecret)); |
||||
|
} |
||||
|
|
||||
|
protected override IAcsClient GetSecurityTokenClient(string regionId, string accessKeyId, string accessKeySecret, string securityToken) |
||||
|
{ |
||||
|
var profile = DefaultProfile.GetProfile(regionId); |
||||
|
var credentials = new BasicSessionCredentials(accessKeyId, accessKeySecret, securityToken); |
||||
|
return new DefaultAcsClient(profile, credentials); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace LINYUN.Abp.Aliyun |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class AliyunBasicSessionCredentialsCacheItem |
||||
|
{ |
||||
|
private readonly static string _cacheKey; |
||||
|
public static string CacheKey => _cacheKey; |
||||
|
public string AccessKeyId { get; set; } |
||||
|
public string AccessKeySecret { get; set; } |
||||
|
public string SecurityToken { get; set; } |
||||
|
|
||||
|
static AliyunBasicSessionCredentialsCacheItem() |
||||
|
{ |
||||
|
_cacheKey = Guid.NewGuid().ToString("N"); |
||||
|
} |
||||
|
|
||||
|
public AliyunBasicSessionCredentialsCacheItem() |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public AliyunBasicSessionCredentialsCacheItem(string accessKeyId, string accessKeySecret, string securityToken) |
||||
|
{ |
||||
|
AccessKeyId = accessKeyId; |
||||
|
AccessKeySecret = accessKeySecret; |
||||
|
SecurityToken = securityToken; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,180 @@ |
|||||
|
using Aliyun.Acs.Core; |
||||
|
using Aliyun.Acs.Core.Auth.Sts; |
||||
|
using Aliyun.Acs.Core.Http; |
||||
|
using Aliyun.Acs.Core.Profile; |
||||
|
using LINYUN.Abp.Aliyun.Settings; |
||||
|
using Microsoft.Extensions.Caching.Distributed; |
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Caching; |
||||
|
using Volo.Abp.Settings; |
||||
|
|
||||
|
namespace LINYUN.Abp.Aliyun |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 阿里云通用客户端构建工厂
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TClient"></typeparam>
|
||||
|
public abstract class AliyunClientFactory<TClient> |
||||
|
{ |
||||
|
protected ISettingProvider SettingProvider { get; } |
||||
|
protected IDistributedCache<AliyunBasicSessionCredentialsCacheItem> Cache { get; } |
||||
|
public AliyunClientFactory( |
||||
|
ISettingProvider settingProvider, |
||||
|
IDistributedCache<AliyunBasicSessionCredentialsCacheItem> cache) |
||||
|
{ |
||||
|
Cache = cache; |
||||
|
SettingProvider = settingProvider; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<TClient> CreateAsync() |
||||
|
{ |
||||
|
var regionId = await SettingProvider.GetOrNullAsync(AliyunSettingNames.Authorization.RegionId); |
||||
|
var accessKey = await SettingProvider.GetOrNullAsync(AliyunSettingNames.Authorization.AccessKeyId); |
||||
|
var accessKeySecret = await SettingProvider.GetOrNullAsync(AliyunSettingNames.Authorization.AccessKeySecret); |
||||
|
|
||||
|
Check.NotNullOrWhiteSpace(regionId, AliyunSettingNames.Authorization.RegionId); |
||||
|
Check.NotNullOrWhiteSpace(accessKey, AliyunSettingNames.Authorization.AccessKeyId); |
||||
|
Check.NotNullOrWhiteSpace(accessKeySecret, AliyunSettingNames.Authorization.AccessKeySecret); |
||||
|
|
||||
|
if (await SettingProvider.IsTrueAsync(AliyunSettingNames.Authorization.UseSecurityTokenService)) |
||||
|
{ |
||||
|
var cacheItem = await GetCacheItemAsync(accessKey, accessKeySecret, regionId); |
||||
|
|
||||
|
return GetSecurityTokenClient(regionId, cacheItem.AccessKeyId, cacheItem.AccessKeySecret, cacheItem.SecurityToken); |
||||
|
} |
||||
|
|
||||
|
return GetClient(regionId, accessKey, accessKeySecret); |
||||
|
} |
||||
|
|
||||
|
protected abstract TClient GetClient(string regionId, string accessKeyId, string accessKeySecret); |
||||
|
|
||||
|
protected abstract TClient GetSecurityTokenClient(string regionId, string accessKeyId, string accessKeySecret, string securityToken); |
||||
|
|
||||
|
protected virtual async Task<AliyunBasicSessionCredentialsCacheItem> GetCacheItemAsync(string accessKeyId, string accessKeySecret, string regionId) |
||||
|
{ |
||||
|
var cacheItem = await Cache.GetAsync(AliyunBasicSessionCredentialsCacheItem.CacheKey); |
||||
|
if (cacheItem == null) |
||||
|
{ |
||||
|
var roleArn = await SettingProvider.GetOrNullAsync(AliyunSettingNames.Authorization.RamRoleArn); |
||||
|
var roleSession = await SettingProvider.GetOrNullAsync(AliyunSettingNames.Authorization.RoleSessionName); |
||||
|
Check.NotNullOrWhiteSpace(roleArn, AliyunSettingNames.Authorization.RamRoleArn); |
||||
|
|
||||
|
var policy = await SettingProvider.GetOrNullAsync(AliyunSettingNames.Authorization.Policy); |
||||
|
var durationSeconds = await SettingProvider.GetAsync(AliyunSettingNames.Authorization.DurationSeconds, 3000); |
||||
|
|
||||
|
var profile = DefaultProfile.GetProfile(regionId, accessKeyId, accessKeySecret); |
||||
|
var request = new AssumeRoleRequest |
||||
|
{ |
||||
|
AcceptFormat = FormatType.JSON, |
||||
|
RoleArn = roleArn, |
||||
|
RoleSessionName = roleSession, |
||||
|
DurationSeconds = durationSeconds, |
||||
|
Policy = policy.IsNullOrWhiteSpace() ? null : policy |
||||
|
}; |
||||
|
|
||||
|
var client = new DefaultAcsClient(profile); |
||||
|
var response = client.GetAcsResponse(request); |
||||
|
|
||||
|
cacheItem = new AliyunBasicSessionCredentialsCacheItem( |
||||
|
response.Credentials.AccessKeyId, |
||||
|
response.Credentials.AccessKeySecret, |
||||
|
response.Credentials.SecurityToken); |
||||
|
|
||||
|
await Cache.SetAsync( |
||||
|
AliyunBasicSessionCredentialsCacheItem.CacheKey, |
||||
|
cacheItem, |
||||
|
new DistributedCacheEntryOptions |
||||
|
{ |
||||
|
AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(durationSeconds - 10) |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
return cacheItem; |
||||
|
} |
||||
|
} |
||||
|
/// <summary>
|
||||
|
/// 阿里云通用客户端构建工厂
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TClient">客户端类型</typeparam>
|
||||
|
/// <typeparam name="TConfiguration">客户端参数类型</typeparam>
|
||||
|
public abstract class AliyunClientFactory<TClient, TConfiguration> |
||||
|
{ |
||||
|
protected ISettingProvider SettingProvider { get; } |
||||
|
protected IDistributedCache<AliyunBasicSessionCredentialsCacheItem> Cache { get; } |
||||
|
public AliyunClientFactory( |
||||
|
ISettingProvider settingProvider, |
||||
|
IDistributedCache<AliyunBasicSessionCredentialsCacheItem> cache) |
||||
|
{ |
||||
|
Cache = cache; |
||||
|
SettingProvider = settingProvider; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<TClient> CreateAsync(TConfiguration configuration) |
||||
|
{ |
||||
|
var regionId = await SettingProvider.GetOrNullAsync(AliyunSettingNames.Authorization.RegionId); |
||||
|
var accessKey = await SettingProvider.GetOrNullAsync(AliyunSettingNames.Authorization.AccessKeyId); |
||||
|
var accessKeySecret = await SettingProvider.GetOrNullAsync(AliyunSettingNames.Authorization.AccessKeySecret); |
||||
|
|
||||
|
Check.NotNullOrWhiteSpace(regionId, AliyunSettingNames.Authorization.RegionId); |
||||
|
Check.NotNullOrWhiteSpace(accessKey, AliyunSettingNames.Authorization.AccessKeyId); |
||||
|
Check.NotNullOrWhiteSpace(accessKeySecret, AliyunSettingNames.Authorization.AccessKeySecret); |
||||
|
|
||||
|
if (await SettingProvider.IsTrueAsync(AliyunSettingNames.Authorization.UseSecurityTokenService)) |
||||
|
{ |
||||
|
var cacheItem = await GetCacheItemAsync(accessKey, accessKeySecret, regionId); |
||||
|
|
||||
|
return GetSecurityTokenClient(configuration, regionId, cacheItem.AccessKeyId, cacheItem.AccessKeySecret, cacheItem.SecurityToken); |
||||
|
} |
||||
|
|
||||
|
return GetClient(configuration, regionId, accessKey, accessKeySecret); |
||||
|
} |
||||
|
|
||||
|
protected abstract TClient GetClient(TConfiguration configuration, string regionId, string accessKeyId, string accessKeySecret); |
||||
|
|
||||
|
protected abstract TClient GetSecurityTokenClient(TConfiguration configuration, string regionId, string accessKeyId, string accessKeySecret, string securityToken); |
||||
|
|
||||
|
protected virtual async Task<AliyunBasicSessionCredentialsCacheItem> GetCacheItemAsync(string accessKeyId, string accessKeySecret, string regionId) |
||||
|
{ |
||||
|
var cacheItem = await Cache.GetAsync(AliyunBasicSessionCredentialsCacheItem.CacheKey); |
||||
|
if (cacheItem == null) |
||||
|
{ |
||||
|
var roleArn = await SettingProvider.GetOrNullAsync(AliyunSettingNames.Authorization.RamRoleArn); |
||||
|
var roleSession = await SettingProvider.GetOrNullAsync(AliyunSettingNames.Authorization.RoleSessionName); |
||||
|
Check.NotNullOrWhiteSpace(roleArn, AliyunSettingNames.Authorization.RamRoleArn); |
||||
|
|
||||
|
var policy = await SettingProvider.GetOrNullAsync(AliyunSettingNames.Authorization.Policy); |
||||
|
var durationSeconds = await SettingProvider.GetAsync(AliyunSettingNames.Authorization.DurationSeconds, 3000); |
||||
|
|
||||
|
var profile = DefaultProfile.GetProfile(regionId, accessKeyId, accessKeySecret); |
||||
|
var request = new AssumeRoleRequest |
||||
|
{ |
||||
|
AcceptFormat = FormatType.JSON, |
||||
|
RoleArn = roleArn, |
||||
|
RoleSessionName = roleSession, |
||||
|
DurationSeconds = durationSeconds, |
||||
|
Policy = policy.IsNullOrWhiteSpace() ? null : policy |
||||
|
}; |
||||
|
|
||||
|
var client = new DefaultAcsClient(profile); |
||||
|
var response = client.GetAcsResponse(request); |
||||
|
|
||||
|
cacheItem = new AliyunBasicSessionCredentialsCacheItem( |
||||
|
response.Credentials.AccessKeyId, |
||||
|
response.Credentials.AccessKeySecret, |
||||
|
response.Credentials.SecurityToken); |
||||
|
|
||||
|
await Cache.SetAsync( |
||||
|
AliyunBasicSessionCredentialsCacheItem.CacheKey, |
||||
|
cacheItem, |
||||
|
new DistributedCacheEntryOptions |
||||
|
{ |
||||
|
AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(durationSeconds - 10) |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
return cacheItem; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using Aliyun.Acs.Core; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINYUN.Abp.Aliyun |
||||
|
{ |
||||
|
public interface IAcsClientFactory |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 构造一个通用的Acs客户端调用
|
||||
|
/// 通过CommonRequest调用可以不需要集成其他SDK包
|
||||
|
/// </summary>
|
||||
|
/// <returns></returns>
|
||||
|
Task<IAcsClient> CreateAsync(); |
||||
|
} |
||||
|
} |
||||
@ -1,5 +1,23 @@ |
|||||
{ |
{ |
||||
"culture": "en", |
"culture": "en", |
||||
"texts": { |
"texts": { |
||||
|
"DisplayName:Authorization": "Authorization", |
||||
|
"Description:Authorization": "Authorization", |
||||
|
"DisplayName:RegionId": "Region Id", |
||||
|
"Description:RegionId": "Region Id", |
||||
|
"DisplayName:AccessKeyId": "AccessKey Id", |
||||
|
"Description:AccessKeyId": "AccessKey Id", |
||||
|
"DisplayName:AccessKeySecret": "AccessKey Secret", |
||||
|
"Description:AccessKeySecret": "AccessKey Secret", |
||||
|
"DisplayName:UseSecurityTokenService": "Use STS Token", |
||||
|
"Description:UseSecurityTokenService": "Use STS Token", |
||||
|
"DisplayName:RamRoleArn": "Ram Role Arn", |
||||
|
"Description:RamRoleArn": "Ram Role Arn", |
||||
|
"DisplayName:RoleSessionName": "Role Session Name", |
||||
|
"Description:RoleSessionName": "Role Session Name", |
||||
|
"DisplayName:DurationSeconds": "Duration Seconds,in seconds", |
||||
|
"Description:DurationSeconds": "Duration Seconds,in seconds", |
||||
|
"DisplayName:Policy": "Policy", |
||||
|
"Description:Policy": "Policy" |
||||
} |
} |
||||
} |
} |
||||
@ -1,5 +1,23 @@ |
|||||
{ |
{ |
||||
"culture": "zh-Hans", |
"culture": "zh-Hans", |
||||
"texts": { |
"texts": { |
||||
|
"DisplayName:Authorization": "阿里云身份认证凭据", |
||||
|
"Description:Authorization": "阿里云身份认证凭据", |
||||
|
"DisplayName:RegionId": "地域ID", |
||||
|
"Description:RegionId": "正在使用的地域ID", |
||||
|
"DisplayName:AccessKeyId": "AccessKey Id", |
||||
|
"Description:AccessKeyId": "访问密钥标识", |
||||
|
"DisplayName:AccessKeySecret": "AccessKey Secret", |
||||
|
"Description:AccessKeySecret": "访问密钥", |
||||
|
"DisplayName:UseSecurityTokenService": "使用STS Token访问", |
||||
|
"Description:UseSecurityTokenService": "使用STS Token访问", |
||||
|
"DisplayName:RamRoleArn": "角色全局资源描述符", |
||||
|
"Description:RamRoleArn": "格式:acs:ram::$accountID:role/$roleName/$RoleSessionName,详情见阿里云访问控制API", |
||||
|
"DisplayName:RoleSessionName": "角色的临时身份", |
||||
|
"Description:RoleSessionName": "此参数用来区分不同的令牌,可用于用户级别的访问审计", |
||||
|
"DisplayName:DurationSeconds": "过期时间,单位为秒。", |
||||
|
"Description:DurationSeconds": "过期时间最小值为900秒,默认3600秒", |
||||
|
"DisplayName:Policy": "权限策略", |
||||
|
"Description:Policy": "生成STS Token时可以指定一个额外的权限策略,以进一步限制STS Token的权限" |
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,81 @@ |
|||||
|
using LINYUN.Abp.Aliyun.Localization; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.Settings; |
||||
|
|
||||
|
namespace LINYUN.Abp.Aliyun.Settings |
||||
|
{ |
||||
|
public class AliyunSettingProvider : SettingDefinitionProvider |
||||
|
{ |
||||
|
public override void Define(ISettingDefinitionContext context) |
||||
|
{ |
||||
|
context.Add(CreateAliyunSettings()); |
||||
|
} |
||||
|
|
||||
|
private SettingDefinition[] CreateAliyunSettings() |
||||
|
{ |
||||
|
return new SettingDefinition[] |
||||
|
{ |
||||
|
new SettingDefinition( |
||||
|
AliyunSettingNames.Authorization.AccessKeyId, |
||||
|
displayName: L("DisplayName:AccessKeyId"), |
||||
|
description: L("Description:AccessKeyId"), |
||||
|
isVisibleToClients: false, |
||||
|
isEncrypted: true |
||||
|
), |
||||
|
new SettingDefinition( |
||||
|
AliyunSettingNames.Authorization.AccessKeySecret, |
||||
|
displayName: L("DisplayName:AccessKeySecret"), |
||||
|
description: L("Description:AccessKeySecret"), |
||||
|
isVisibleToClients: false, |
||||
|
isEncrypted: true |
||||
|
), |
||||
|
new SettingDefinition( |
||||
|
AliyunSettingNames.Authorization.DurationSeconds, |
||||
|
defaultValue: "3000", |
||||
|
displayName: L("DisplayName:DurationSeconds"), |
||||
|
description: L("Description:DurationSeconds"), |
||||
|
isVisibleToClients: false |
||||
|
), |
||||
|
new SettingDefinition( |
||||
|
AliyunSettingNames.Authorization.Policy, |
||||
|
displayName: L("DisplayName:Policy"), |
||||
|
description: L("Description:Policy"), |
||||
|
isVisibleToClients: false, |
||||
|
isEncrypted: true |
||||
|
), |
||||
|
new SettingDefinition( |
||||
|
AliyunSettingNames.Authorization.RamRoleArn, |
||||
|
displayName: L("DisplayName:RamRoleArn"), |
||||
|
description: L("Description:RamRoleArn"), |
||||
|
isVisibleToClients: false, |
||||
|
isEncrypted: true |
||||
|
), |
||||
|
new SettingDefinition( |
||||
|
AliyunSettingNames.Authorization.RegionId, |
||||
|
displayName: L("DisplayName:RegionId"), |
||||
|
description: L("Description:RegionId"), |
||||
|
isVisibleToClients: false |
||||
|
), |
||||
|
new SettingDefinition( |
||||
|
AliyunSettingNames.Authorization.RoleSessionName, |
||||
|
displayName: L("DisplayName:RoleSessionName"), |
||||
|
description: L("Description:RoleSessionName"), |
||||
|
isVisibleToClients: false, |
||||
|
isEncrypted: true |
||||
|
), |
||||
|
new SettingDefinition( |
||||
|
AliyunSettingNames.Authorization.UseSecurityTokenService, |
||||
|
defaultValue: true.ToString(), |
||||
|
displayName: L("DisplayName:UseSecurityTokenService"), |
||||
|
description: L("Description:UseSecurityTokenService"), |
||||
|
isVisibleToClients: false |
||||
|
), |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
private ILocalizableString L(string name) |
||||
|
{ |
||||
|
return LocalizableString.Create<AliyunResource>(name); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
# LINGYUN.Abp.Aliyun |
||||
|
|
||||
|
阿里云sdk集成 |
||||
|
|
||||
|
参照:https://help.aliyun.com/document_detail/28763.html |
||||
|
|
||||
|
## 配置使用 |
||||
|
|
||||
|
模块按需引用 |
||||
|
|
||||
|
```csharp |
||||
|
[DependsOn(typeof(AbpAliyunModule))] |
||||
|
public class YouProjectModule : AbpModule |
||||
|
{ |
||||
|
// other |
||||
|
} |
||||
|
``` |
||||
|
## 配置项说明 |
||||
|
|
||||
|
* AliyunSettingNames.Authorization.RegionId 可选,区域,默认 default |
||||
|
* AliyunSettingNames.Authorization.AccessKeyId 必须,阿里云RAM账号的AccessKey ID |
||||
|
* AliyunSettingNames.Authorization.AccessKeySecret 必须,RAM账号的AccessKey Secret |
||||
|
* AliyunSettingNames.Authorization.UseSecurityTokenService 可选,建议,使用STS Token访问,按照阿里云文档,建议使用Sts Token访问API,默认false |
||||
|
* AliyunSettingNames.Authorization.RamRoleArn 可选,启用Sts Token之后必须配置,阿里云RAM角色ARN |
||||
|
* AliyunSettingNames.Authorization.RoleSessionName 可选,启用Sts Token之后的用户自定义令牌名称,用于访问审计 |
||||
|
* AliyunSettingNames.Authorization.DurationSeconds 可选,用户令牌的过期时间,单位为秒,默认3000 |
||||
|
* AliyunSettingNames.Authorization.Policy 可选,权限策略,为json字符串 |
||||
|
|
||||
|
## 其他 |
||||
|
|
||||
|
网络因素在高并发下可能会出现预期外的异常,考虑使用二级缓存 |
||||
@ -0,0 +1,15 @@ |
|||||
|
using Aliyun.OSS; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.BlobStoring.Aliyun |
||||
|
{ |
||||
|
public interface IOssClientFactory |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 通过配置信息构建Oss客户端调用
|
||||
|
/// </summary>
|
||||
|
/// <param name="configuration"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task<IOss> CreateAsync(AliyunBlobProviderConfiguration configuration); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,50 @@ |
|||||
|
using Aliyun.OSS; |
||||
|
using LINYUN.Abp.Aliyun; |
||||
|
using Volo.Abp.Caching; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Settings; |
||||
|
|
||||
|
namespace LINGYUN.Abp.BlobStoring.Aliyun |
||||
|
{ |
||||
|
public class OssClientFactory : AliyunClientFactory<IOss, AliyunBlobProviderConfiguration>, IOssClientFactory, ITransientDependency |
||||
|
{ |
||||
|
public OssClientFactory( |
||||
|
ISettingProvider settingProvider, |
||||
|
IDistributedCache<AliyunBasicSessionCredentialsCacheItem> cache) |
||||
|
: base(settingProvider, cache) |
||||
|
{ |
||||
|
} |
||||
|
/// <summary>
|
||||
|
/// 普通方式构建Oss客户端
|
||||
|
/// </summary>
|
||||
|
/// <param name="configuration"></param>
|
||||
|
/// <param name="regionId"></param>
|
||||
|
/// <param name="accessKeyId"></param>
|
||||
|
/// <param name="accessKeySecret"></param>
|
||||
|
/// <returns></returns>
|
||||
|
protected override IOss GetClient(AliyunBlobProviderConfiguration configuration, string regionId, string accessKeyId, string accessKeySecret) |
||||
|
{ |
||||
|
return new OssClient( |
||||
|
configuration.Endpoint, |
||||
|
accessKeyId, |
||||
|
accessKeySecret); |
||||
|
} |
||||
|
/// <summary>
|
||||
|
/// 通过用户安全令牌构建Oss客户端
|
||||
|
/// </summary>
|
||||
|
/// <param name="configuration"></param>
|
||||
|
/// <param name="regionId"></param>
|
||||
|
/// <param name="accessKeyId"></param>
|
||||
|
/// <param name="accessKeySecret"></param>
|
||||
|
/// <param name="securityToken"></param>
|
||||
|
/// <returns></returns>
|
||||
|
protected override IOss GetSecurityTokenClient(AliyunBlobProviderConfiguration configuration, string regionId, string accessKeyId, string accessKeySecret, string securityToken) |
||||
|
{ |
||||
|
return new OssClient( |
||||
|
configuration.Endpoint, |
||||
|
accessKeyId, |
||||
|
accessKeySecret, |
||||
|
securityToken); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,28 +1,12 @@ |
|||||
using Microsoft.Extensions.Logging; |
using LINYUN.Abp.Aliyun; |
||||
using Volo.Abp; |
|
||||
using Volo.Abp.ExceptionHandling; |
|
||||
using Volo.Abp.Localization; |
|
||||
using Volo.Abp.Logging; |
|
||||
|
|
||||
namespace LINYUN.Abp.Sms.Aliyun |
namespace LINYUN.Abp.Sms.Aliyun |
||||
{ |
{ |
||||
public class AliyunSmsException : AbpException, IHasErrorCode, ILocalizeErrorMessage, IHasLogLevel |
public class AliyunSmsException : AbpAliyunException |
||||
{ |
{ |
||||
public AliyunSmsException(string code, string message) |
public AliyunSmsException(string code, string message) |
||||
:base(message) |
:base(code, message) |
||||
{ |
{ |
||||
Code = code; |
|
||||
LogLevel = LogLevel.Warning; |
|
||||
} |
|
||||
|
|
||||
public LogLevel LogLevel { get; set; } |
|
||||
|
|
||||
public string Code { get; } |
|
||||
|
|
||||
public string LocalizeMessage(LocalizationContext context) |
|
||||
{ |
|
||||
return AliyunSmsResponse.GetErrorMessage(Code, Message) |
|
||||
.Localize(context.LocalizerFactory); |
|
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,38 +0,0 @@ |
|||||
namespace LINYUN.Abp.Sms.Aliyun |
|
||||
{ |
|
||||
public class AliyunSmsOptions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// 区域Id
|
|
||||
/// </summary>
|
|
||||
public string RegionId { get; set; } = "default"; |
|
||||
/// <summary>
|
|
||||
/// 阿里云sms服务域名
|
|
||||
/// </summary>
|
|
||||
public string Domain { get; set; } = "dysmsapi.aliyuncs.com"; |
|
||||
/// <summary>
|
|
||||
/// 调用方法名称
|
|
||||
/// </summary>
|
|
||||
public string ActionName { get; set; } = "SendSms"; |
|
||||
/// <summary>
|
|
||||
/// 默认版本号
|
|
||||
/// </summary>
|
|
||||
public string Version { get; set; } = "2017-05-25"; |
|
||||
/// <summary>
|
|
||||
/// 默认签名
|
|
||||
/// </summary>
|
|
||||
public string DefaultSignName { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 默认短信模板号
|
|
||||
/// </summary>
|
|
||||
public string DefaultTemplateCode { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 开发人员号码,当应用处于开发模式时,默认所有信息都会发送到此号码
|
|
||||
/// </summary>
|
|
||||
public string DeveloperPhoneNumber { get; set; } = "13800138000"; |
|
||||
/// <summary>
|
|
||||
/// 展示错误给客户端
|
|
||||
/// </summary>
|
|
||||
public bool VisableErrorToClient { get; set; } = false; |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,43 @@ |
|||||
|
using LINYUN.Abp.Aliyun.Settings; |
||||
|
|
||||
|
namespace LINYUN.Abp.Sms.Aliyun.Settings |
||||
|
{ |
||||
|
public static class AliyunSmsSettingNames |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 短信服务
|
||||
|
/// </summary>
|
||||
|
public class Sms |
||||
|
{ |
||||
|
public const string Prefix = AliyunSettingNames.Prefix + ".Sms"; |
||||
|
/// <summary>
|
||||
|
/// 阿里云sms服务域名
|
||||
|
/// </summary>
|
||||
|
public const string Domain = Prefix + ".Domain"; |
||||
|
/// <summary>
|
||||
|
/// 调用方法名称
|
||||
|
/// </summary>
|
||||
|
public const string ActionName = Prefix + ".ActionName"; |
||||
|
/// <summary>
|
||||
|
/// 默认版本号
|
||||
|
/// </summary>
|
||||
|
public const string Version = Prefix + ".Version"; |
||||
|
/// <summary>
|
||||
|
/// 默认签名
|
||||
|
/// </summary>
|
||||
|
public const string DefaultSignName = Prefix + ".DefaultSignName"; |
||||
|
/// <summary>
|
||||
|
/// 默认短信模板号
|
||||
|
/// </summary>
|
||||
|
public const string DefaultTemplateCode = Prefix + ".DefaultTemplateCode"; |
||||
|
/// <summary>
|
||||
|
/// 默认号码
|
||||
|
/// </summary>
|
||||
|
public const string DefaultPhoneNumber = Prefix + ".DefaultPhoneNumber"; |
||||
|
/// <summary>
|
||||
|
/// 展示错误给客户端
|
||||
|
/// </summary>
|
||||
|
public const string VisableErrorToClient = Prefix + ".VisableErrorToClient"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,74 @@ |
|||||
|
using LINYUN.Abp.Aliyun.Localization; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.Settings; |
||||
|
|
||||
|
namespace LINYUN.Abp.Sms.Aliyun.Settings |
||||
|
{ |
||||
|
public class AliyunSmsSettingProvider : SettingDefinitionProvider |
||||
|
{ |
||||
|
public override void Define(ISettingDefinitionContext context) |
||||
|
{ |
||||
|
context.Add(CreateAliyunSettings()); |
||||
|
} |
||||
|
|
||||
|
private SettingDefinition[] CreateAliyunSettings() |
||||
|
{ |
||||
|
return new SettingDefinition[] |
||||
|
{ |
||||
|
new SettingDefinition( |
||||
|
AliyunSmsSettingNames.Sms.ActionName, |
||||
|
defaultValue: "SendSms", |
||||
|
displayName: L("DisplayName:ActionName"), |
||||
|
description: L("Description:ActionName"), |
||||
|
isVisibleToClients: false |
||||
|
), |
||||
|
new SettingDefinition( |
||||
|
AliyunSmsSettingNames.Sms.DefaultSignName, |
||||
|
displayName: L("DisplayName:DefaultSignName"), |
||||
|
description: L("Description:DefaultSignName"), |
||||
|
isVisibleToClients: false, |
||||
|
isEncrypted: true |
||||
|
), |
||||
|
new SettingDefinition( |
||||
|
AliyunSmsSettingNames.Sms.DefaultTemplateCode, |
||||
|
displayName: L("DisplayName:DefaultTemplateCode"), |
||||
|
description: L("Description:DefaultTemplateCode"), |
||||
|
isVisibleToClients: false, |
||||
|
isEncrypted: true |
||||
|
), |
||||
|
new SettingDefinition( |
||||
|
AliyunSmsSettingNames.Sms.DefaultPhoneNumber, |
||||
|
displayName: L("DisplayName:DefaultPhoneNumber"), |
||||
|
description: L("Description:DefaultPhoneNumber"), |
||||
|
isVisibleToClients: false |
||||
|
), |
||||
|
new SettingDefinition( |
||||
|
AliyunSmsSettingNames.Sms.Domain, |
||||
|
defaultValue: "dysmsapi.aliyuncs.com", |
||||
|
displayName: L("DisplayName:Domain"), |
||||
|
description: L("Description:Domain"), |
||||
|
isVisibleToClients: false |
||||
|
), |
||||
|
new SettingDefinition( |
||||
|
AliyunSmsSettingNames.Sms.Version, |
||||
|
defaultValue: "2017-05-25", |
||||
|
displayName: L("DisplayName:Version"), |
||||
|
description: L("Description:Version"), |
||||
|
isVisibleToClients: false |
||||
|
), |
||||
|
new SettingDefinition( |
||||
|
AliyunSmsSettingNames.Sms.VisableErrorToClient, |
||||
|
defaultValue: false.ToString(), |
||||
|
displayName: L("DisplayName:VisableErrorToClient"), |
||||
|
description: L("Description:VisableErrorToClient"), |
||||
|
isVisibleToClients: false |
||||
|
) |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
private ILocalizableString L(string name) |
||||
|
{ |
||||
|
return LocalizableString.Create<AliyunResource>(name); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.Security; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Encryption.Console |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpSecurityModule))] |
||||
|
public class AbpEncryptionConsoleModule : AbpModule |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<OutputType>Exe</OutputType> |
||||
|
<TargetFramework>netcoreapp3.1</TargetFramework> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.Security" Version="4.1.2" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,42 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using System; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Security.Encryption; |
||||
|
using static System.Console; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Encryption.Console |
||||
|
{ |
||||
|
class Program |
||||
|
{ |
||||
|
static void Main(string[] args) |
||||
|
{ |
||||
|
WriteLine("Hello World!"); |
||||
|
|
||||
|
var application = AbpApplicationFactory.Create<AbpEncryptionConsoleModule>(); |
||||
|
|
||||
|
application.Initialize(); |
||||
|
|
||||
|
WriteLine("D:解密 E:加密"); |
||||
|
|
||||
|
var opt = ReadLine(); |
||||
|
bool en = false; |
||||
|
if ("E".Equals(opt, StringComparison.InvariantCultureIgnoreCase)) |
||||
|
{ |
||||
|
en = true; |
||||
|
WriteLine("请输入需要加密的字符串"); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
WriteLine("请输入需要解密的字符串"); |
||||
|
} |
||||
|
|
||||
|
var sourceChr = ReadLine(); |
||||
|
var encryptionService = application.ServiceProvider.GetRequiredService<IStringEncryptionService>(); |
||||
|
WriteLine(en ? encryptionService.Encrypt(sourceChr) : encryptionService.Decrypt(sourceChr)); |
||||
|
|
||||
|
application.Shutdown(); |
||||
|
|
||||
|
ReadKey(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>net5.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
<IsPackable>false</IsPackable> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\modules\cloud-aliyun\LINGYUN.Abp.Aliyun\LINGYUN.Abp.Aliyun.csproj" /> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.TestBase\LINGYUN.Abp.TestsBase.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,8 @@ |
|||||
|
using LINGYUN.Abp.Tests; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Aliyun |
||||
|
{ |
||||
|
public class AbpAliyunTestBase : AbpTestsBase<AbpAliyunTestModule> |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
using LINGYUN.Abp.Tests; |
||||
|
using Microsoft.Extensions.Configuration; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Aliyun |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpAliyunModule), |
||||
|
typeof(AbpTestsBaseModule))] |
||||
|
public class AbpAliyunTestModule : AbpModule |
||||
|
{ |
||||
|
public override void PreConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
var configurationOptions = new AbpConfigurationBuilderOptions |
||||
|
{ |
||||
|
BasePath = @"D:\Projects\Development\Abp\Aliyun", |
||||
|
EnvironmentName = "Development" |
||||
|
}; |
||||
|
|
||||
|
context.Services.ReplaceConfiguration(ConfigurationHelper.BuildConfiguration(configurationOptions)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,52 @@ |
|||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using System; |
||||
|
using System.Diagnostics; |
||||
|
|
||||
|
namespace LINGYUN.Abp.EntityFrameworkCore.Tests |
||||
|
{ |
||||
|
public class EfCoreLoggerFactory : ILoggerFactory |
||||
|
{ |
||||
|
public void AddProvider(ILoggerProvider provider) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public ILogger CreateLogger(string categoryName) |
||||
|
{ |
||||
|
return new EfCoreLogger(categoryName);//创建EFLogger类的实例
|
||||
|
} |
||||
|
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class EfCoreLogger : ILogger |
||||
|
{ |
||||
|
private readonly string _categoryName; |
||||
|
|
||||
|
public EfCoreLogger(string categoryName) => this._categoryName = categoryName; |
||||
|
|
||||
|
public bool IsEnabled(LogLevel logLevel) => true; |
||||
|
|
||||
|
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter) |
||||
|
{ |
||||
|
var logContent = formatter(state, exception); |
||||
|
|
||||
|
Debug.WriteLine(""); |
||||
|
// Console.ForegroundColor = logLevel == LogLevel.Warning || logLevel == LogLevel.Error ? ConsoleColor.Red : ConsoleColor.Green;
|
||||
|
Debug.WriteLine(logContent); |
||||
|
} |
||||
|
|
||||
|
public IDisposable BeginScope<TState>(TState state) => null; |
||||
|
} |
||||
|
|
||||
|
public static class EFCoreLoggerExtensions |
||||
|
{ |
||||
|
public static DbContextOptionsBuilder UseEFCoreLogger(this DbContextOptionsBuilder builder) |
||||
|
{ |
||||
|
return builder.UseLoggerFactory(new EfCoreLoggerFactory()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>net5.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
<IsPackable>false</IsPackable> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\modules\common\LINGYUN.Abp.Sms.Aliyun\LINGYUN.Abp.Sms.Aliyun.csproj" /> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.Aliyun.Tests\LINGYUN.Abp.Aliyun.Tests.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,8 @@ |
|||||
|
using LINGYUN.Abp.Tests; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Sms.Aliyun |
||||
|
{ |
||||
|
public class AbpAliyunTestBase : AbpTestsBase<AbpAliyunSmsTestModule> |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using LINGYUN.Abp.Aliyun; |
||||
|
using LINYUN.Abp.Sms.Aliyun; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Sms.Aliyun |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpAliyunTestModule), |
||||
|
typeof(AbpAliyunSmsModule))] |
||||
|
public class AbpAliyunSmsTestModule : AbpModule |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,43 @@ |
|||||
|
using Microsoft.Extensions.Configuration; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Sms; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Sms.Aliyun |
||||
|
{ |
||||
|
public class AliyunSmsSenderTests : AbpAliyunTestBase |
||||
|
{ |
||||
|
protected ISmsSender SmsSender { get; } |
||||
|
protected IConfiguration Configuration { get; } |
||||
|
|
||||
|
public AliyunSmsSenderTests() |
||||
|
{ |
||||
|
SmsSender = GetRequiredService<ISmsSender>(); |
||||
|
Configuration = GetRequiredService<IConfiguration>(); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 阿里云短信测试
|
||||
|
/// </summary>
|
||||
|
/// <param name="code"></param>
|
||||
|
/// <returns></returns>
|
||||
|
[Theory] |
||||
|
[InlineData("123456")] |
||||
|
public async Task Send_Test(string code) |
||||
|
{ |
||||
|
var signName = Configuration["Aliyun:Sms:Sender:SignName"]; |
||||
|
var phone = Configuration["Aliyun:Sms:Sender:PhoneNumber"]; |
||||
|
var template = Configuration["Aliyun:Sms:Sender:TemplateCode"]; |
||||
|
|
||||
|
await SmsSender.SendAsync( |
||||
|
signName, |
||||
|
template, |
||||
|
phone, |
||||
|
new Dictionary<string, object> |
||||
|
{ |
||||
|
{ "code", code } |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>net5.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
<IsPackable>false</IsPackable> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" /> |
||||
|
<PackageReference Include="NSubstitute" Version="4.2.1" /> |
||||
|
<PackageReference Include="Shouldly" Version="3.0.2" /> |
||||
|
<PackageReference Include="xunit" Version="2.4.1" /> |
||||
|
<PackageReference Include="xunit.extensibility.execution" Version="2.4.1" /> |
||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\modules\platform\LINGYUN.Platform.Domain\LINGYUN.Platform.Domain.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,40 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Data; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.Threading; |
||||
|
|
||||
|
namespace LINGYUN.Platform |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(PlatformDomainModule) |
||||
|
)] |
||||
|
public class PlatformDomainTestModule : AbpModule |
||||
|
{ |
||||
|
public override void OnApplicationInitialization(ApplicationInitializationContext context) |
||||
|
{ |
||||
|
SeedTestData(context); |
||||
|
} |
||||
|
|
||||
|
private static void SeedTestData(ApplicationInitializationContext context) |
||||
|
{ |
||||
|
using (var scope = context.ServiceProvider.CreateScope()) |
||||
|
{ |
||||
|
var dataSeeder = scope.ServiceProvider.GetRequiredService<IDataSeeder>(); |
||||
|
AsyncHelper.RunSync(async () => |
||||
|
{ |
||||
|
// 预置宿主数据
|
||||
|
await dataSeeder.SeedAsync(); |
||||
|
// 预置租户数据
|
||||
|
await dataSeeder.SeedAsync(PlatformTestsConsts.TenantId); |
||||
|
}); |
||||
|
AsyncHelper.RunSync(async () => |
||||
|
{ |
||||
|
await scope.ServiceProvider |
||||
|
.GetRequiredService<PlatformTestsDataBuilder>() |
||||
|
.BuildAsync(); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace LINGYUN.Platform |
||||
|
{ |
||||
|
public static class PlatformTestsConsts |
||||
|
{ |
||||
|
public static Guid User1Id { get; } = Guid.NewGuid(); |
||||
|
|
||||
|
public static Guid User2Id { get; } = Guid.NewGuid(); |
||||
|
|
||||
|
public static Guid TenantId { get; } = Guid.NewGuid(); |
||||
|
|
||||
|
public static string Role1Name { get; } = "TestRole1"; |
||||
|
|
||||
|
public static string Role2Name { get; } = "TestRole2"; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,65 @@ |
|||||
|
using LINGYUN.Platform.Menus; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
using Volo.Abp.Uow; |
||||
|
|
||||
|
namespace LINGYUN.Platform |
||||
|
{ |
||||
|
public class PlatformTestsDataBuilder : ITransientDependency |
||||
|
{ |
||||
|
private readonly ICurrentTenant _currentTenant; |
||||
|
|
||||
|
private readonly MenuManager _menuManager; |
||||
|
private readonly IMenuRepository _menuRepository; |
||||
|
|
||||
|
public PlatformTestsDataBuilder( |
||||
|
ICurrentTenant currentTenant, |
||||
|
MenuManager menuManager, |
||||
|
IMenuRepository menuRepository) |
||||
|
{ |
||||
|
_currentTenant = currentTenant; |
||||
|
|
||||
|
_menuManager = menuManager; |
||||
|
_menuRepository = menuRepository; |
||||
|
} |
||||
|
|
||||
|
[UnitOfWork] |
||||
|
public async Task BuildAsync() |
||||
|
{ |
||||
|
var adminMenu = await _menuRepository.FindByNameAsync("admin"); |
||||
|
|
||||
|
var saasMenu = await _menuRepository.FindByNameAsync("saas"); |
||||
|
await SetRoleMenusAsync(PlatformTestsConsts.Role1Name, new Guid[] { saasMenu.Id }); |
||||
|
await SetRoleMenusAsync(PlatformTestsConsts.Role2Name, new Guid[] { adminMenu.Id, saasMenu.Id }); |
||||
|
|
||||
|
await SetUserMenusAsync(PlatformTestsConsts.User1Id, new Guid[] { saasMenu.Id }); |
||||
|
|
||||
|
|
||||
|
using (_currentTenant.Change(PlatformTestsConsts.TenantId)) |
||||
|
{ |
||||
|
var tenantAdminMenu = await _menuRepository.FindByNameAsync("admin"); |
||||
|
await SetUserMenusAsync(PlatformTestsConsts.User2Id, new Guid[] { tenantAdminMenu.Id }); |
||||
|
await SetRoleMenusAsync(PlatformTestsConsts.Role1Name, new Guid[] { tenantAdminMenu.Id }); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private async Task SetUserMenusAsync(Guid userId, IEnumerable<Guid> menusIds) |
||||
|
{ |
||||
|
await _menuManager |
||||
|
.SetUserMenusAsync( |
||||
|
userId, |
||||
|
menusIds); |
||||
|
} |
||||
|
|
||||
|
private async Task SetRoleMenusAsync(string roleName, IEnumerable<Guid> menusIds) |
||||
|
{ |
||||
|
await _menuManager |
||||
|
.SetRoleMenusAsync( |
||||
|
roleName, |
||||
|
menusIds); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>net5.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
<IsPackable>false</IsPackable> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" /> |
||||
|
<PackageReference Include="NSubstitute" Version="4.2.1" /> |
||||
|
<PackageReference Include="Shouldly" Version="3.0.2" /> |
||||
|
<PackageReference Include="xunit" Version="2.4.1" /> |
||||
|
<PackageReference Include="xunit.extensibility.execution" Version="2.4.1" /> |
||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\modules\platform\LINGYUN.Platform.EntityFrameworkCore\LINGYUN.Platform.EntityFrameworkCore.csproj" /> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.EntityFrameworkCore.Tests\LINGYUN.Abp.EntityFrameworkCore.Tests.csproj" /> |
||||
|
<ProjectReference Include="..\LINGYUN.Platform.Domain.Tests\LINGYUN.Platform.Domain.Tests.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,9 @@ |
|||||
|
using LINGYUN.Abp.Tests; |
||||
|
|
||||
|
namespace LINGYUN.Platform.EntityFrameworkCore |
||||
|
{ |
||||
|
public class PlatformEntityFrameworkCoreTestBase : AbpTestsBase<PlatformEntityFrameworkCoreTestModule> |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
using LINGYUN.Abp.EntityFrameworkCore.Tests; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Platform.EntityFrameworkCore |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(PlatformDomainTestModule), |
||||
|
typeof(PlatformEntityFrameworkCoreModule), |
||||
|
typeof(AbpEntityFrameworkCoreTestModule) |
||||
|
)] |
||||
|
public class PlatformEntityFrameworkCoreTestModule : AbpModule |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,68 @@ |
|||||
|
using LINGYUN.Platform.EntityFrameworkCore; |
||||
|
using Shouldly; |
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Menus |
||||
|
{ |
||||
|
public class EfCoreUserMenuRepositoryTests : PlatformEntityFrameworkCoreTestBase |
||||
|
{ |
||||
|
protected ICurrentTenant CurrentTenant { get; } |
||||
|
protected IUserMenuRepository Repository { get; } |
||||
|
protected IMenuRepository MenuRepository { get; } |
||||
|
protected MenuManager MenuManager { get; } |
||||
|
|
||||
|
public EfCoreUserMenuRepositoryTests() |
||||
|
{ |
||||
|
MenuManager = GetRequiredService<MenuManager>(); |
||||
|
Repository = GetRequiredService<IUserMenuRepository>(); |
||||
|
MenuRepository = GetRequiredService<IMenuRepository>(); |
||||
|
|
||||
|
CurrentTenant = GetRequiredService<ICurrentTenant>(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task UserHasInMenuAsync_Test() |
||||
|
{ |
||||
|
(await Repository.UserHasInMenuAsync(PlatformTestsConsts.User1Id, "saas")).ShouldBeTrue(); |
||||
|
(await Repository.UserHasInMenuAsync(PlatformTestsConsts.User2Id, "admin")).ShouldBeFalse(); |
||||
|
|
||||
|
using (CurrentTenant.Change(PlatformTestsConsts.TenantId)) |
||||
|
{ |
||||
|
(await Repository.UserHasInMenuAsync(PlatformTestsConsts.User2Id, "admin")).ShouldBeTrue(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task SetMemberMenusAsync_Test() |
||||
|
{ |
||||
|
var adminMenu = await MenuRepository.FindByNameAsync("admin"); |
||||
|
var saasMenu = await MenuRepository.FindByNameAsync("saas"); |
||||
|
|
||||
|
await MenuManager.SetUserMenusAsync(PlatformTestsConsts.User1Id, new Guid[] { adminMenu.Id}); |
||||
|
await MenuManager.SetUserMenusAsync(PlatformTestsConsts.User2Id, new Guid[] { adminMenu.Id, saasMenu.Id }); |
||||
|
|
||||
|
(await Repository.UserHasInMenuAsync(PlatformTestsConsts.User1Id, "admin")).ShouldBeTrue(); |
||||
|
(await Repository.UserHasInMenuAsync(PlatformTestsConsts.User2Id, "admin")).ShouldBeTrue(); |
||||
|
(await Repository.UserHasInMenuAsync(PlatformTestsConsts.User2Id, "saas")).ShouldBeTrue(); |
||||
|
|
||||
|
using (CurrentTenant.Change(PlatformTestsConsts.TenantId)) |
||||
|
{ |
||||
|
(await Repository.UserHasInMenuAsync(PlatformTestsConsts.User1Id, "admin")).ShouldBeFalse(); |
||||
|
|
||||
|
var tenantSaasMenu = await MenuRepository.FindByNameAsync("saas"); |
||||
|
|
||||
|
var ss = await Repository.GetListByUserIdAsync(PlatformTestsConsts.User2Id); |
||||
|
|
||||
|
await MenuManager.SetUserMenusAsync(PlatformTestsConsts.User2Id, new Guid[] { tenantSaasMenu.Id }); |
||||
|
|
||||
|
var ss1 = await Repository.GetListByUserIdAsync(PlatformTestsConsts.User2Id); |
||||
|
|
||||
|
(await Repository.UserHasInMenuAsync(PlatformTestsConsts.User2Id, "admin")).ShouldBeFalse(); |
||||
|
(await Repository.UserHasInMenuAsync(PlatformTestsConsts.User2Id, "saas")).ShouldBeTrue(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue