diff --git a/Sanhe.Abp.Framework.sln b/Sanhe.Abp.Framework.sln index 9bc6d96..559081b 100644 --- a/Sanhe.Abp.Framework.sln +++ b/Sanhe.Abp.Framework.sln @@ -63,11 +63,27 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sanhe.Abp.PinyinConverter", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sanhe.Abp.PinyinConverter.ToolGoodWords", "modules\common\Sanhe.Abp.PinyinConverter.ToolGoodWords\Sanhe.Abp.PinyinConverter.ToolGoodWords.csproj", "{EE08FB0C-EDC1-4DEF-B0C8-699F4E7D08AF}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sanhe.Abp.RealTime", "modules\common\Sanhe.Abp.RealTime\Sanhe.Abp.RealTime.csproj", "{C99CF772-210B-4C21-84FE-089B7D038A28}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sanhe.Abp.RealTime", "modules\common\Sanhe.Abp.RealTime\Sanhe.Abp.RealTime.csproj", "{C99CF772-210B-4C21-84FE-089B7D038A28}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sanhe.Abp.IdGenerator", "modules\common\Sanhe.Abp.IdGenerator\Sanhe.Abp.IdGenerator.csproj", "{86CDAB3C-D7EC-4F4B-BCB9-2069DAE1D0FC}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sanhe.Abp.IdGenerator", "modules\common\Sanhe.Abp.IdGenerator\Sanhe.Abp.IdGenerator.csproj", "{86CDAB3C-D7EC-4F4B-BCB9-2069DAE1D0FC}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sanhe.Abp.Notifications", "modules\common\Sanhe.Abp.Notifications\Sanhe.Abp.Notifications.csproj", "{8F9EA0EF-6C02-4017-AEB4-A0B4CB4D5983}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sanhe.Abp.Notifications", "modules\common\Sanhe.Abp.Notifications\Sanhe.Abp.Notifications.csproj", "{8F9EA0EF-6C02-4017-AEB4-A0B4CB4D5983}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "identity", "identity", "{BAA5EE9D-A5C6-45F3-A89B-B3CC30FF3DFE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sanhe.Abp.Identity.Domain.Shared", "modules\identity\Sanhe.Abp.Identity.Domain.Shared\Sanhe.Abp.Identity.Domain.Shared.csproj", "{86E8E59C-FDB8-45E5-B9DE-BEFE51DF05DC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sanhe.Abp.Identity.Domain", "modules\identity\Sanhe.Abp.Identity.Domain\Sanhe.Abp.Identity.Domain.csproj", "{6531A9CD-E1B2-4861-8C31-9561220D088B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sanhe.Abp.Identity.Application.Contracts", "modules\identity\Sanhe.Abp.Identity.Application.Contracts\Sanhe.Abp.Identity.Application.Contracts.csproj", "{CA166F9C-7535-4CB7-B8B5-D01971B8C09F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sanhe.Abp.Identity.Application", "modules\identity\Sanhe.Abp.Identity.Application\Sanhe.Abp.Identity.Application.csproj", "{39102CCF-4AFB-44F2-9D9D-3D2449D71C88}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sanhe.Abp.Identity.EntityFrameworkCore", "modules\identity\Sanhe.Abp.Identity.EntityFrameworkCore\Sanhe.Abp.Identity.EntityFrameworkCore.csproj", "{9C8F2135-A237-41D9-B054-C6170D2CC6B2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sanhe.Abp.Identity.HttpApi", "modules\identity\Sanhe.Abp.Identity.HttpApi\Sanhe.Abp.Identity.HttpApi.csproj", "{F53FC671-99FD-4CD8-915E-5B77619A6C6B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sanhe.Abp.Identity.HttpApi.Client", "modules\identity\Sanhe.Abp.Identity.HttpApi.Client\Sanhe.Abp.Identity.HttpApi.Client.csproj", "{6E5D3C18-45B4-478B-B064-140C5CDDD327}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -163,6 +179,34 @@ Global {8F9EA0EF-6C02-4017-AEB4-A0B4CB4D5983}.Debug|Any CPU.Build.0 = Debug|Any CPU {8F9EA0EF-6C02-4017-AEB4-A0B4CB4D5983}.Release|Any CPU.ActiveCfg = Release|Any CPU {8F9EA0EF-6C02-4017-AEB4-A0B4CB4D5983}.Release|Any CPU.Build.0 = Release|Any CPU + {86E8E59C-FDB8-45E5-B9DE-BEFE51DF05DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {86E8E59C-FDB8-45E5-B9DE-BEFE51DF05DC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {86E8E59C-FDB8-45E5-B9DE-BEFE51DF05DC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {86E8E59C-FDB8-45E5-B9DE-BEFE51DF05DC}.Release|Any CPU.Build.0 = Release|Any CPU + {6531A9CD-E1B2-4861-8C31-9561220D088B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6531A9CD-E1B2-4861-8C31-9561220D088B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6531A9CD-E1B2-4861-8C31-9561220D088B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6531A9CD-E1B2-4861-8C31-9561220D088B}.Release|Any CPU.Build.0 = Release|Any CPU + {CA166F9C-7535-4CB7-B8B5-D01971B8C09F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CA166F9C-7535-4CB7-B8B5-D01971B8C09F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CA166F9C-7535-4CB7-B8B5-D01971B8C09F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CA166F9C-7535-4CB7-B8B5-D01971B8C09F}.Release|Any CPU.Build.0 = Release|Any CPU + {39102CCF-4AFB-44F2-9D9D-3D2449D71C88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39102CCF-4AFB-44F2-9D9D-3D2449D71C88}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39102CCF-4AFB-44F2-9D9D-3D2449D71C88}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39102CCF-4AFB-44F2-9D9D-3D2449D71C88}.Release|Any CPU.Build.0 = Release|Any CPU + {9C8F2135-A237-41D9-B054-C6170D2CC6B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9C8F2135-A237-41D9-B054-C6170D2CC6B2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9C8F2135-A237-41D9-B054-C6170D2CC6B2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9C8F2135-A237-41D9-B054-C6170D2CC6B2}.Release|Any CPU.Build.0 = Release|Any CPU + {F53FC671-99FD-4CD8-915E-5B77619A6C6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F53FC671-99FD-4CD8-915E-5B77619A6C6B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F53FC671-99FD-4CD8-915E-5B77619A6C6B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F53FC671-99FD-4CD8-915E-5B77619A6C6B}.Release|Any CPU.Build.0 = Release|Any CPU + {6E5D3C18-45B4-478B-B064-140C5CDDD327}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6E5D3C18-45B4-478B-B064-140C5CDDD327}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6E5D3C18-45B4-478B-B064-140C5CDDD327}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6E5D3C18-45B4-478B-B064-140C5CDDD327}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -195,6 +239,14 @@ Global {C99CF772-210B-4C21-84FE-089B7D038A28} = {2A768109-31B7-4C52-928C-3023DAB9F254} {86CDAB3C-D7EC-4F4B-BCB9-2069DAE1D0FC} = {2A768109-31B7-4C52-928C-3023DAB9F254} {8F9EA0EF-6C02-4017-AEB4-A0B4CB4D5983} = {2A768109-31B7-4C52-928C-3023DAB9F254} + {BAA5EE9D-A5C6-45F3-A89B-B3CC30FF3DFE} = {F5F5D604-531B-4B57-A88E-C9C5CEEC55D7} + {86E8E59C-FDB8-45E5-B9DE-BEFE51DF05DC} = {BAA5EE9D-A5C6-45F3-A89B-B3CC30FF3DFE} + {6531A9CD-E1B2-4861-8C31-9561220D088B} = {BAA5EE9D-A5C6-45F3-A89B-B3CC30FF3DFE} + {CA166F9C-7535-4CB7-B8B5-D01971B8C09F} = {BAA5EE9D-A5C6-45F3-A89B-B3CC30FF3DFE} + {39102CCF-4AFB-44F2-9D9D-3D2449D71C88} = {BAA5EE9D-A5C6-45F3-A89B-B3CC30FF3DFE} + {9C8F2135-A237-41D9-B054-C6170D2CC6B2} = {BAA5EE9D-A5C6-45F3-A89B-B3CC30FF3DFE} + {F53FC671-99FD-4CD8-915E-5B77619A6C6B} = {BAA5EE9D-A5C6-45F3-A89B-B3CC30FF3DFE} + {6E5D3C18-45B4-478B-B064-140C5CDDD327} = {BAA5EE9D-A5C6-45F3-A89B-B3CC30FF3DFE} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AB69BFDE-9DDB-4D16-8CB8-72472C0319CD} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/FodyWeavers.xml b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/FodyWeavers.xml new file mode 100644 index 0000000..1715698 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe.Abp.Identity.Application.Contracts.csproj b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe.Abp.Identity.Application.Contracts.csproj new file mode 100644 index 0000000..efa9105 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe.Abp.Identity.Application.Contracts.csproj @@ -0,0 +1,18 @@ + + + + + + + netstandard2.0 + + + + + + + + + + + diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/AbpIdentityApplicationContractsModule.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/AbpIdentityApplicationContractsModule.cs new file mode 100644 index 0000000..03b5b49 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/AbpIdentityApplicationContractsModule.cs @@ -0,0 +1,15 @@ +using Volo.Abp.Authorization; +using Volo.Abp.Modularity; + +namespace Sanhe.Abp.Identity +{ + [DependsOn( + typeof(Volo.Abp.Identity.AbpIdentityApplicationContractsModule), + typeof(AbpIdentityDomainSharedModule), + typeof(AbpAuthorizationModule) + )] + public class AbpIdentityApplicationContractsModule : AbpModule + { + + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityClaimDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityClaimDto.cs new file mode 100644 index 0000000..ea99f3a --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityClaimDto.cs @@ -0,0 +1,12 @@ +using System; +using Volo.Abp.Application.Dtos; + +namespace Sanhe.Abp.Identity.Dto +{ + public class IdentityClaimDto : EntityDto + { + public string ClaimType { get; set; } + + public string ClaimValue { get; set; } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityClaimTypeCreateDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityClaimTypeCreateDto.cs new file mode 100644 index 0000000..07f1af8 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityClaimTypeCreateDto.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Identity; +using Volo.Abp.Validation; + +namespace Sanhe.Abp.Identity.Dto +{ + public class IdentityClaimTypeCreateDto : IdentityClaimTypeCreateOrUpdateBaseDto + { + [Required] + [DynamicStringLength(typeof(IdentityClaimTypeConsts), nameof(IdentityClaimTypeConsts.MaxNameLength))] + public string Name { get; set; } + + public bool IsStatic { get; set; } + + public IdentityClaimValueType ValueType { get; set; } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityClaimTypeCreateOrUpdateBaseDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityClaimTypeCreateOrUpdateBaseDto.cs new file mode 100644 index 0000000..523892d --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityClaimTypeCreateOrUpdateBaseDto.cs @@ -0,0 +1,20 @@ +using Volo.Abp.Identity; +using Volo.Abp.ObjectExtending; +using Volo.Abp.Validation; + +namespace Sanhe.Abp.Identity.Dto +{ + public class IdentityClaimTypeCreateOrUpdateBaseDto : ExtensibleObject + { + public bool Required { get; set; } + + [DynamicStringLength(typeof(IdentityClaimTypeConsts), nameof(IdentityClaimTypeConsts.MaxRegexLength))] + public string Regex { get; set; } + + [DynamicStringLength(typeof(IdentityClaimTypeConsts), nameof(IdentityClaimTypeConsts.MaxRegexDescriptionLength))] + public string RegexDescription { get; set; } + + [DynamicStringLength(typeof(IdentityClaimTypeConsts), nameof(IdentityClaimTypeConsts.MaxDescriptionLength))] + public string Description { get; set; } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityClaimTypeDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityClaimTypeDto.cs new file mode 100644 index 0000000..5ea72ad --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityClaimTypeDto.cs @@ -0,0 +1,23 @@ +using System; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Identity; + +namespace Sanhe.Abp.Identity.Dto +{ + public class IdentityClaimTypeDto : ExtensibleEntityDto + { + public string Name { get; set; } + + public bool Required { get; set; } + + public bool IsStatic { get; set; } + + public string Regex { get; set; } + + public string RegexDescription { get; set; } + + public string Description { get; set; } + + public IdentityClaimValueType ValueType { get; set; } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityClaimTypeGetByPagedDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityClaimTypeGetByPagedDto.cs new file mode 100644 index 0000000..905d28e --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityClaimTypeGetByPagedDto.cs @@ -0,0 +1,9 @@ +using Volo.Abp.Application.Dtos; + +namespace Sanhe.Abp.Identity.Dto +{ + public class IdentityClaimTypeGetByPagedDto : PagedAndSortedResultRequestDto + { + public string Filter { get; set; } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityClaimTypeUpdateDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityClaimTypeUpdateDto.cs new file mode 100644 index 0000000..a2022a0 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityClaimTypeUpdateDto.cs @@ -0,0 +1,7 @@ +namespace Sanhe.Abp.Identity.Dto +{ + public class IdentityClaimTypeUpdateDto : IdentityClaimTypeCreateOrUpdateBaseDto + { + + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityRoleAddOrRemoveOrganizationUnitDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityRoleAddOrRemoveOrganizationUnitDto.cs new file mode 100644 index 0000000..678d186 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityRoleAddOrRemoveOrganizationUnitDto.cs @@ -0,0 +1,11 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Sanhe.Abp.Identity.Dto +{ + public class IdentityRoleAddOrRemoveOrganizationUnitDto + { + [Required] + public Guid[] OrganizationUnitIds { get; set; } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityRoleClaimCreateDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityRoleClaimCreateDto.cs new file mode 100644 index 0000000..b175f4a --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityRoleClaimCreateDto.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Identity; +using Volo.Abp.Validation; + +namespace Sanhe.Abp.Identity.Dto +{ + public class IdentityRoleClaimCreateDto + { + [Required] + [DynamicMaxLength(typeof(IdentityRoleClaimConsts), nameof(IdentityRoleClaimConsts.MaxClaimTypeLength))] + public string ClaimType { get; set; } + + [Required] + [DynamicMaxLength(typeof(IdentityRoleClaimConsts), nameof(IdentityRoleClaimConsts.MaxClaimValueLength))] + public string ClaimValue { get; set; } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityRoleClaimDeleteDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityRoleClaimDeleteDto.cs new file mode 100644 index 0000000..ff156ee --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityRoleClaimDeleteDto.cs @@ -0,0 +1,6 @@ +namespace Sanhe.Abp.Identity.Dto +{ + public class IdentityRoleClaimDeleteDto : IdentityRoleClaimCreateDto + { + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityRoleClaimUpdateDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityRoleClaimUpdateDto.cs new file mode 100644 index 0000000..356e023 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityRoleClaimUpdateDto.cs @@ -0,0 +1,13 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Identity; +using Volo.Abp.Validation; + +namespace Sanhe.Abp.Identity.Dto +{ + public class IdentityRoleClaimUpdateDto : IdentityRoleClaimCreateDto + { + [Required] + [DynamicMaxLength(typeof(IdentityRoleClaimConsts), nameof(IdentityRoleClaimConsts.MaxClaimValueLength))] + public string NewClaimValue { get; set; } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityUserClaimCreateDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityUserClaimCreateDto.cs new file mode 100644 index 0000000..270eefc --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityUserClaimCreateDto.cs @@ -0,0 +1,6 @@ +namespace Sanhe.Abp.Identity.Dto +{ + public class IdentityUserClaimCreateDto : IdentityUserClaimCreateOrUpdateDto + { + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityUserClaimCreateOrUpdateDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityUserClaimCreateOrUpdateDto.cs new file mode 100644 index 0000000..f7d9c5c --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityUserClaimCreateOrUpdateDto.cs @@ -0,0 +1,16 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Identity; +using Volo.Abp.Validation; + +namespace Sanhe.Abp.Identity.Dto +{ + public abstract class IdentityUserClaimCreateOrUpdateDto + { + [Required] + [DynamicMaxLength(typeof(IdentityUserClaimConsts), nameof(IdentityUserClaimConsts.MaxClaimTypeLength))] + public string ClaimType { get; set; } + + [DynamicMaxLength(typeof(IdentityUserClaimConsts), nameof(IdentityUserClaimConsts.MaxClaimValueLength))] + public string ClaimValue { get; set; } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityUserClaimDeleteDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityUserClaimDeleteDto.cs new file mode 100644 index 0000000..7879c5f --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityUserClaimDeleteDto.cs @@ -0,0 +1,7 @@ +namespace Sanhe.Abp.Identity.Dto +{ + public class IdentityUserClaimDeleteDto : IdentityUserClaimCreateDto + { + + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityUserClaimUpdateDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityUserClaimUpdateDto.cs new file mode 100644 index 0000000..180ca0f --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityUserClaimUpdateDto.cs @@ -0,0 +1,11 @@ +using Volo.Abp.Identity; +using Volo.Abp.Validation; + +namespace Sanhe.Abp.Identity.Dto +{ + public class IdentityUserClaimUpdateDto : IdentityUserClaimCreateOrUpdateDto + { + [DynamicMaxLength(typeof(IdentityUserClaimConsts), nameof(IdentityUserClaimConsts.MaxClaimValueLength))] + public string NewClaimValue { get; set; } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityUserOrganizationUnitUpdateDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityUserOrganizationUnitUpdateDto.cs new file mode 100644 index 0000000..1d53d47 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/IdentityUserOrganizationUnitUpdateDto.cs @@ -0,0 +1,11 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Sanhe.Abp.Identity.Dto +{ + public class IdentityUserOrganizationUnitUpdateDto + { + [Required] + public Guid[] OrganizationUnitIds { get; set; } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitAddRoleDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitAddRoleDto.cs new file mode 100644 index 0000000..5f6057b --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitAddRoleDto.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Sanhe.Abp.Identity.Dto +{ + public class OrganizationUnitAddRoleDto + { + [Required] + public List RoleIds { get; set; } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitAddUserDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitAddUserDto.cs new file mode 100644 index 0000000..c92f406 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitAddUserDto.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Sanhe.Abp.Identity.Dto +{ + public class OrganizationUnitAddUserDto + { + [Required] + public List UserIds { get; set; } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitCreateDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitCreateDto.cs new file mode 100644 index 0000000..ed39c11 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitCreateDto.cs @@ -0,0 +1,17 @@ +using System; +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Identity; +using Volo.Abp.ObjectExtending; +using Volo.Abp.Validation; + +namespace Sanhe.Abp.Identity.Dto +{ + public class OrganizationUnitCreateDto : ExtensibleObject + { + [Required] + [DynamicStringLength(typeof(OrganizationUnitConsts), nameof(OrganizationUnitConsts.MaxDisplayNameLength))] + public string DisplayName { get; set; } + + public Guid? ParentId { get; set; } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitDto.cs new file mode 100644 index 0000000..b1d089c --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitDto.cs @@ -0,0 +1,12 @@ +using System; +using Volo.Abp.Application.Dtos; + +namespace Sanhe.Abp.Identity.Dto +{ + public class OrganizationUnitDto : ExtensibleAuditedEntityDto + { + public Guid? ParentId { get; set; } + public string Code { get; set; } + public string DisplayName { get; set; } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitGetByPagedDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitGetByPagedDto.cs new file mode 100644 index 0000000..f16773d --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitGetByPagedDto.cs @@ -0,0 +1,9 @@ +using Volo.Abp.Application.Dtos; + +namespace Sanhe.Abp.Identity.Dto +{ + public class OrganizationUnitGetByPagedDto : PagedAndSortedResultRequestDto + { + public string Filter { get; set; } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitGetChildrenDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitGetChildrenDto.cs new file mode 100644 index 0000000..0075777 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitGetChildrenDto.cs @@ -0,0 +1,13 @@ +using System; +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Application.Dtos; + +namespace Sanhe.Abp.Identity.Dto +{ + public class OrganizationUnitGetChildrenDto : IEntityDto + { + [Required] + public Guid Id { get; set; } + public bool Recursive { get; set; } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitGetUnaddedRoleByPagedDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitGetUnaddedRoleByPagedDto.cs new file mode 100644 index 0000000..1ac76c2 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitGetUnaddedRoleByPagedDto.cs @@ -0,0 +1,10 @@ +using Volo.Abp.Application.Dtos; + +namespace Sanhe.Abp.Identity.Dto +{ + public class OrganizationUnitGetUnaddedRoleByPagedDto : PagedAndSortedResultRequestDto + { + + public string Filter { get; set; } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitGetUnaddedUserByPagedDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitGetUnaddedUserByPagedDto.cs new file mode 100644 index 0000000..99c96de --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitGetUnaddedUserByPagedDto.cs @@ -0,0 +1,9 @@ +using Volo.Abp.Application.Dtos; + +namespace Sanhe.Abp.Identity.Dto +{ + public class OrganizationUnitGetUnaddedUserByPagedDto : PagedAndSortedResultRequestDto + { + public string Filter { get; set; } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitMoveDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitMoveDto.cs new file mode 100644 index 0000000..e7c4588 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitMoveDto.cs @@ -0,0 +1,9 @@ +using System; + +namespace Sanhe.Abp.Identity.Dto +{ + public class OrganizationUnitMoveDto + { + public Guid? ParentId { get; set; } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitUpdateDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitUpdateDto.cs new file mode 100644 index 0000000..db980bd --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/OrganizationUnitUpdateDto.cs @@ -0,0 +1,9 @@ +using Volo.Abp.ObjectExtending; + +namespace Sanhe.Abp.Identity.Dto +{ + public class OrganizationUnitUpdateDto : ExtensibleObject + { + public string DisplayName { get; set; } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/TwoFactorEnabledDto.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/TwoFactorEnabledDto.cs new file mode 100644 index 0000000..0711d46 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/Dto/TwoFactorEnabledDto.cs @@ -0,0 +1,7 @@ +namespace Sanhe.Abp.Identity.Dto +{ + public class TwoFactorEnabledDto + { + public bool Enabled { get; set; } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/IIdentityClaimTypeAppService.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/IIdentityClaimTypeAppService.cs new file mode 100644 index 0000000..3ad0da6 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/IIdentityClaimTypeAppService.cs @@ -0,0 +1,18 @@ +using Sanhe.Abp.Identity.Dto; +using System; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; + +namespace Sanhe.Abp.Identity +{ + public interface IIdentityClaimTypeAppService : ICrudAppService< + IdentityClaimTypeDto, + Guid, + IdentityClaimTypeGetByPagedDto, + IdentityClaimTypeCreateDto, + IdentityClaimTypeUpdateDto> + { + Task> GetAllListAsync(); + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/IIdentityRoleAppService.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/IIdentityRoleAppService.cs new file mode 100644 index 0000000..7dc7b01 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/IIdentityRoleAppService.cs @@ -0,0 +1,33 @@ +using Sanhe.Abp.Identity.Dto; +using System; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; + +namespace Sanhe.Abp.Identity +{ + public interface IIdentityRoleAppService : IApplicationService + { + #region OrganizationUnit + + Task> GetOrganizationUnitsAsync(Guid id); + + Task SetOrganizationUnitsAsync(Guid id, IdentityRoleAddOrRemoveOrganizationUnitDto input); + + Task RemoveOrganizationUnitsAsync(Guid id, Guid ouId); + + #endregion + + #region ClaimType + + Task> GetClaimsAsync(Guid id); + + Task AddClaimAsync(Guid id, IdentityRoleClaimCreateDto input); + + Task UpdateClaimAsync(Guid id, IdentityRoleClaimUpdateDto input); + + Task DeleteClaimAsync(Guid id, IdentityRoleClaimDeleteDto input); + + #endregion + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/IIdentityUserAppService.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/IIdentityUserAppService.cs new file mode 100644 index 0000000..69f715c --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/IIdentityUserAppService.cs @@ -0,0 +1,63 @@ +using Sanhe.Abp.Identity.Dto; +using System; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; + +namespace Sanhe.Abp.Identity +{ + public interface IIdentityUserAppService : IApplicationService + { + + #region OrganizationUnit + + Task> GetOrganizationUnitsAsync(Guid id); + + Task SetOrganizationUnitsAsync(Guid id, IdentityUserOrganizationUnitUpdateDto input); + + Task RemoveOrganizationUnitsAsync(Guid id, Guid ouId); + + #endregion + + #region ClaimType + + Task> GetClaimsAsync(Guid id); + + Task AddClaimAsync(Guid id, IdentityUserClaimCreateDto input); + + Task UpdateClaimAsync(Guid id, IdentityUserClaimUpdateDto input); + + Task DeleteClaimAsync(Guid id, IdentityUserClaimDeleteDto input); + + #endregion + + /// + /// 变更用户双因素验证选项 + /// + /// + /// + /// + Task ChangeTwoFactorEnabledAsync(Guid id, TwoFactorEnabledDto input); + /// + /// 变更用户密码 + /// + /// + /// + /// + /// TODO: 移除api,改为重置用户密码 + // Task ChangePasswordAsync(Guid id, ChangePasswordInput input); + /// + /// 锁定 + /// + /// + /// 锁定时长 + /// + Task LockAsync(Guid id, int seconds); + /// + /// 解除锁定 + /// + /// + /// + Task UnLockAsync(Guid id); + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/IOrganizationUnitAppService.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/IOrganizationUnitAppService.cs new file mode 100644 index 0000000..130a52e --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/IOrganizationUnitAppService.cs @@ -0,0 +1,41 @@ +using Sanhe.Abp.Identity.Dto; +using System; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; +using Volo.Abp.Identity; + +namespace Sanhe.Abp.Identity +{ + public interface IOrganizationUnitAppService : ICrudAppService< + OrganizationUnitDto, + Guid, + OrganizationUnitGetByPagedDto, + OrganizationUnitCreateDto, + OrganizationUnitUpdateDto> + { + Task> GetAllListAsync(); + + Task GetLastChildOrNullAsync(Guid? parentId); + + Task MoveAsync(Guid id, OrganizationUnitMoveDto input); + + Task> GetRootAsync(); + + Task> FindChildrenAsync(OrganizationUnitGetChildrenDto input); + + Task> GetRoleNamesAsync(Guid id); + + Task> GetUnaddedRolesAsync(Guid id, OrganizationUnitGetUnaddedRoleByPagedDto input); + + Task> GetRolesAsync(Guid id, PagedAndSortedResultRequestDto input); + + Task AddRolesAsync(Guid id, OrganizationUnitAddRoleDto input); + + Task> GetUnaddedUsersAsync(Guid id, OrganizationUnitGetUnaddedUserByPagedDto input); + + Task> GetUsersAsync(Guid id, GetIdentityUsersInput input); + + Task AddUsersAsync(Guid id, OrganizationUnitAddUserDto input); + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/IdentityPermissionDefinitionProvider.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/IdentityPermissionDefinitionProvider.cs new file mode 100644 index 0000000..8d5a930 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/IdentityPermissionDefinitionProvider.cs @@ -0,0 +1,50 @@ +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Identity.Localization; +using Volo.Abp.Localization; +using Volo.Abp.MultiTenancy; + +namespace Sanhe.Abp.Identity +{ + public class IdentityPermissionDefinitionProvider : PermissionDefinitionProvider + { + public override void Define(IPermissionDefinitionContext context) + { + var identityGroup = context.GetGroupOrNull(Volo.Abp.Identity.IdentityPermissions.GroupName); + if (identityGroup != null) + { + var userPermission = identityGroup.GetPermissionOrNull(Volo.Abp.Identity.IdentityPermissions.Users.Default); + if (userPermission != null) + { + userPermission.AddChild(IdentityPermissions.Users.ManageClaims, L("Permission:ManageClaims")); + userPermission.AddChild(IdentityPermissions.Users.ManageOrganizationUnits, L("Permission:ManageOrganizationUnits")); + } + + var rolePermission = identityGroup.GetPermissionOrNull(Volo.Abp.Identity.IdentityPermissions.Roles.Default); + if (rolePermission != null) + { + rolePermission.AddChild(IdentityPermissions.Roles.ManageClaims, L("Permission:ManageClaims")); + rolePermission.AddChild(IdentityPermissions.Roles.ManageOrganizationUnits, L("Permission:ManageOrganizationUnits")); + } + + var organizationUnitPermission = identityGroup.AddPermission(IdentityPermissions.OrganizationUnits.Default, L("Permission:OrganizationUnitManagement")); + organizationUnitPermission.AddChild(IdentityPermissions.OrganizationUnits.Create, L("Permission:Create")); + organizationUnitPermission.AddChild(IdentityPermissions.OrganizationUnits.Update, L("Permission:Edit")); + organizationUnitPermission.AddChild(IdentityPermissions.OrganizationUnits.Delete, L("Permission:Delete")); + organizationUnitPermission.AddChild(IdentityPermissions.OrganizationUnits.ManageRoles, L("Permission:ManageRoles")); + organizationUnitPermission.AddChild(IdentityPermissions.OrganizationUnits.ManageUsers, L("Permission:ManageUsers")); + organizationUnitPermission.AddChild(IdentityPermissions.OrganizationUnits.ManagePermissions, L("Permission:ChangePermissions")); + + // 2020-10-23 修复Bug 租户用户也必须能查询自定义的声明, 管理权限只能为主机 + var identityClaimType = identityGroup.AddPermission(IdentityPermissions.IdentityClaimType.Default, L("Permission:IdentityClaimTypeManagement")); + identityClaimType.AddChild(IdentityPermissions.IdentityClaimType.Create, L("Permission:Create"), MultiTenancySides.Host); + identityClaimType.AddChild(IdentityPermissions.IdentityClaimType.Update, L("Permission:Edit"), MultiTenancySides.Host); + identityClaimType.AddChild(IdentityPermissions.IdentityClaimType.Delete, L("Permission:Delete"), MultiTenancySides.Host); + } + } + + private static LocalizableString L(string name) + { + return LocalizableString.Create(name); + } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/IdentityPermissions.cs b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/IdentityPermissions.cs new file mode 100644 index 0000000..e8f99ba --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application.Contracts/Sanhe/Abp/Identity/IdentityPermissions.cs @@ -0,0 +1,43 @@ +using Volo.Abp.Reflection; + +namespace Sanhe.Abp.Identity +{ + public class IdentityPermissions + { + public static class Roles + { + public const string ManageClaims = Volo.Abp.Identity.IdentityPermissions.Roles.Default + ".ManageClaims"; + public const string ManageOrganizationUnits = Volo.Abp.Identity.IdentityPermissions.Roles.Default + ".ManageOrganizationUnits"; + } + + public static class Users + { + public const string ManageClaims = Volo.Abp.Identity.IdentityPermissions.Users.Default + ".ManageClaims"; + public const string ManageOrganizationUnits = Volo.Abp.Identity.IdentityPermissions.Users.Default + ".ManageOrganizationUnits"; + } + + public static class OrganizationUnits + { + public const string Default = Volo.Abp.Identity.IdentityPermissions.GroupName + ".OrganizationUnits"; + public const string Create = Default + ".Create"; + public const string Update = Default + ".Update"; + public const string Delete = Default + ".Delete"; + public const string ManageUsers = Default + ".ManageUsers"; + public const string ManageRoles = Default + ".ManageRoles"; + public const string ManagePermissions = Default + ".ManagePermissions"; + } + + public static class IdentityClaimType + { + public const string Default = Volo.Abp.Identity.IdentityPermissions.GroupName + ".IdentityClaimTypes"; + public const string Create = Default + ".Create"; + public const string Update = Default + ".Update"; + public const string Delete = Default + ".Delete"; + } + + public static string[] GetAll() + { + return ReflectionHelper.GetPublicConstantsRecursively(typeof(IdentityPermissions)); + } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application/FodyWeavers.xml b/modules/identity/Sanhe.Abp.Identity.Application/FodyWeavers.xml new file mode 100644 index 0000000..1715698 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/identity/Sanhe.Abp.Identity.Application/Sanhe.Abp.Identity.Application.csproj b/modules/identity/Sanhe.Abp.Identity.Application/Sanhe.Abp.Identity.Application.csproj new file mode 100644 index 0000000..f312f0d --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application/Sanhe.Abp.Identity.Application.csproj @@ -0,0 +1,20 @@ + + + + + + + netstandard2.0 + + + + + + + + + + + + + diff --git a/modules/identity/Sanhe.Abp.Identity.Application/Sanhe/Abp/Identity/AbpIdentityApplicationModule.cs b/modules/identity/Sanhe.Abp.Identity.Application/Sanhe/Abp/Identity/AbpIdentityApplicationModule.cs new file mode 100644 index 0000000..e833581 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application/Sanhe/Abp/Identity/AbpIdentityApplicationModule.cs @@ -0,0 +1,42 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.AutoMapper; +using Volo.Abp.Modularity; + +namespace Sanhe.Abp.Identity +{ + [DependsOn( + typeof(Volo.Abp.Identity.AbpIdentityApplicationModule), + typeof(AbpIdentityApplicationContractsModule), + typeof(AbpIdentityDomainModule))] + public class AbpIdentityApplicationModule : AbpModule + { + // private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner(); + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddAutoMapperObjectMapper(); + + Configure(options => + { + options.AddProfile(validate: true); + }); + } + + //public override void PostConfigureServices(ServiceConfigurationContext context) + //{ + // OneTimeRunner.Run(() => + // { + // ObjectExtensionManager.Instance + // .AddOrUpdateProperty( + // new[] + // { + // typeof(IdentityUserDto), + // typeof(IdentityUserCreateDto), + // typeof(IdentityUserUpdateDto), + // typeof(ProfileDto), + // typeof(UpdateProfileDto) + // }, + // ExtensionIdentityUserConsts.AvatarUrlField); + // }); + //} + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application/Sanhe/Abp/Identity/AbpIdentityApplicationModuleAutoMapperProfile.cs b/modules/identity/Sanhe.Abp.Identity.Application/Sanhe/Abp/Identity/AbpIdentityApplicationModuleAutoMapperProfile.cs new file mode 100644 index 0000000..002093e --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application/Sanhe/Abp/Identity/AbpIdentityApplicationModuleAutoMapperProfile.cs @@ -0,0 +1,26 @@ +using AutoMapper; +using Sanhe.Abp.Identity.Dto; +using Volo.Abp.Identity; + +namespace Sanhe.Abp.Identity +{ + public class AbpIdentityApplicationModuleAutoMapperProfile : Profile + { + public AbpIdentityApplicationModuleAutoMapperProfile() + { + CreateMap() + .MapExtraProperties(); + CreateMap(); + CreateMap(); + + CreateMap() + .MapExtraProperties(); + + CreateMap() + .MapExtraProperties(); + + CreateMap() + .MapExtraProperties(); + } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application/Sanhe/Abp/Identity/IdentityClaimTypeAppService.cs b/modules/identity/Sanhe.Abp.Identity.Application/Sanhe/Abp/Identity/IdentityClaimTypeAppService.cs new file mode 100644 index 0000000..1d2062d --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application/Sanhe/Abp/Identity/IdentityClaimTypeAppService.cs @@ -0,0 +1,130 @@ +using Microsoft.AspNetCore.Authorization; +using Sanhe.Abp.Identity.Dto; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Identity; + +namespace Sanhe.Abp.Identity +{ + [Authorize(IdentityPermissions.IdentityClaimType.Default)] + public class IdentityClaimTypeAppService : IdentityAppServiceBase, IIdentityClaimTypeAppService + { + protected IdentityClaimTypeManager IdentityClaimTypeManager { get; } + + protected IIdentityClaimTypeRepository IdentityClaimTypeRepository { get; } + + public IdentityClaimTypeAppService( + IdentityClaimTypeManager identityClaimTypeManager, + IIdentityClaimTypeRepository identityClaimTypeRepository) + { + IdentityClaimTypeManager = identityClaimTypeManager; + IdentityClaimTypeRepository = identityClaimTypeRepository; + } + + [Authorize(IdentityPermissions.IdentityClaimType.Create)] + public virtual async Task CreateAsync(IdentityClaimTypeCreateDto input) + { + if (await IdentityClaimTypeRepository.AnyAsync(input.Name)) + { + throw new UserFriendlyException(L["IdentityClaimTypeAlreadyExists", input.Name]); + } + var identityClaimType = new IdentityClaimType( + GuidGenerator.Create(), + input.Name, + input.Required, + input.IsStatic, + input.Regex, + input.RegexDescription, + input.Description, + input.ValueType + ); + identityClaimType = await IdentityClaimTypeManager.CreateAsync(identityClaimType); + await CurrentUnitOfWork.SaveChangesAsync(); + + return ObjectMapper.Map(identityClaimType); + } + + [Authorize(IdentityPermissions.IdentityClaimType.Delete)] + public virtual async Task DeleteAsync(Guid id) + { + var identityClaimType = await IdentityClaimTypeRepository.FindAsync(id); + if (identityClaimType == null) + { + return; + } + CheckDeletionClaimType(identityClaimType); + await IdentityClaimTypeRepository.DeleteAsync(identityClaimType); + } + + public virtual async Task GetAsync(Guid id) + { + var identityClaimType = await IdentityClaimTypeRepository.FindAsync(id); + + return ObjectMapper.Map(identityClaimType); + } + + public virtual async Task> GetAllListAsync() + { + var identityClaimTypes = await IdentityClaimTypeRepository + .GetListAsync(); + + return new ListResultDto( + ObjectMapper.Map, List>(identityClaimTypes)); + } + + public virtual async Task> GetListAsync(IdentityClaimTypeGetByPagedDto input) + { + var identityClaimTypeCount = await IdentityClaimTypeRepository.GetCountAsync(input.Filter); + + var identityClaimTypes = await IdentityClaimTypeRepository + .GetListAsync(input.Sorting, input.MaxResultCount, input.SkipCount, input.Filter); + + return new PagedResultDto(identityClaimTypeCount, + ObjectMapper.Map, List>(identityClaimTypes)); + } + + [Authorize(IdentityPermissions.IdentityClaimType.Update)] + public virtual async Task UpdateAsync(Guid id, IdentityClaimTypeUpdateDto input) + { + var identityClaimType = await IdentityClaimTypeRepository.GetAsync(id); + CheckChangingClaimType(identityClaimType); + identityClaimType.Required = input.Required; + if (!string.Equals(identityClaimType.Regex, input.Regex, StringComparison.InvariantCultureIgnoreCase)) + { + identityClaimType.Regex = input.Regex; + } + if (!string.Equals(identityClaimType.RegexDescription, input.RegexDescription, StringComparison.InvariantCultureIgnoreCase)) + { + identityClaimType.RegexDescription = input.RegexDescription; + } + if (!string.Equals(identityClaimType.Description, input.Description, StringComparison.InvariantCultureIgnoreCase)) + { + identityClaimType.Description = input.Description; + } + + identityClaimType = await IdentityClaimTypeManager.UpdateAsync(identityClaimType); + await CurrentUnitOfWork.SaveChangesAsync(); + + return ObjectMapper.Map(identityClaimType); + } + + protected virtual void CheckChangingClaimType(IdentityClaimType claimType) + { + if (claimType.IsStatic) + { + throw new BusinessException(IdentityErrorCodes.StaticClaimTypeChange); + } + } + + protected virtual void CheckDeletionClaimType(IdentityClaimType claimType) + { + if (claimType.IsStatic) + { + throw new BusinessException(IdentityErrorCodes.StaticClaimTypeDeletion); + } + } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application/Sanhe/Abp/Identity/IdentityRoleAppService.cs b/modules/identity/Sanhe.Abp.Identity.Application/Sanhe/Abp/Identity/IdentityRoleAppService.cs new file mode 100644 index 0000000..84db852 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application/Sanhe/Abp/Identity/IdentityRoleAppService.cs @@ -0,0 +1,124 @@ +using Microsoft.AspNetCore.Authorization; +using Sanhe.Abp.Identity.Dto; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Identity; + +namespace Sanhe.Abp.Identity +{ + [Authorize(Volo.Abp.Identity.IdentityPermissions.Roles.Default)] + public class IdentityRoleAppService : IdentityAppServiceBase, IIdentityRoleAppService + { + protected IIdentityRoleRepository IdentityRoleRepository { get; } + protected OrganizationUnitManager OrganizationUnitManager { get; } + protected IOrganizationUnitRepository OrganizationUnitRepository { get; } + public IdentityRoleAppService( + IIdentityRoleRepository roleRepository, + OrganizationUnitManager organizationUnitManager) + { + OrganizationUnitManager = organizationUnitManager; + IdentityRoleRepository = roleRepository; + } + + #region OrganizationUnit + + [Authorize(IdentityPermissions.Roles.ManageOrganizationUnits)] + public virtual async Task> GetOrganizationUnitsAsync(Guid id) + { + var organizationUnits = await IdentityRoleRepository.GetOrganizationUnitsAsync(id); + + return new ListResultDto( + ObjectMapper.Map, List>(organizationUnits)); + } + + [Authorize(IdentityPermissions.Roles.ManageOrganizationUnits)] + public virtual async Task SetOrganizationUnitsAsync(Guid id, IdentityRoleAddOrRemoveOrganizationUnitDto input) + { + var organizationUnits = await IdentityRoleRepository.GetOrganizationUnitsAsync(id, true); + + var notInRoleOuIds = input.OrganizationUnitIds.Where(ouid => !organizationUnits.Any(ou => ou.Id.Equals(ouid))); + + foreach (var ouId in notInRoleOuIds) + { + await OrganizationUnitManager.AddRoleToOrganizationUnitAsync(id, ouId); + } + + var removeRoleOriganzationUnits = organizationUnits.Where(ou => !input.OrganizationUnitIds.Contains(ou.Id)); + foreach (var origanzationUnit in removeRoleOriganzationUnits) + { + origanzationUnit.RemoveRole(id); + } + + await CurrentUnitOfWork.SaveChangesAsync(); + } + + [Authorize(IdentityPermissions.Roles.ManageOrganizationUnits)] + public virtual async Task RemoveOrganizationUnitsAsync(Guid id, Guid ouId) + { + await OrganizationUnitManager.RemoveRoleFromOrganizationUnitAsync(id, ouId); + + await CurrentUnitOfWork.SaveChangesAsync(); + } + + #endregion + + #region ClaimType + + public virtual async Task> GetClaimsAsync(Guid id) + { + var role = await IdentityRoleRepository.GetAsync(id); + + return new ListResultDto(ObjectMapper.Map, List>(role.Claims)); + } + + [Authorize(IdentityPermissions.Roles.ManageClaims)] + public virtual async Task AddClaimAsync(Guid id, IdentityRoleClaimCreateDto input) + { + var role = await IdentityRoleRepository.GetAsync(id); + var claim = new Claim(input.ClaimType, input.ClaimValue); + if (role.FindClaim(claim) != null) + { + throw new UserFriendlyException(L["RoleClaimAlreadyExists"]); + } + + role.AddClaim(GuidGenerator, claim); + await IdentityRoleRepository.UpdateAsync(role); + + await CurrentUnitOfWork.SaveChangesAsync(); + } + + [Authorize(IdentityPermissions.Roles.ManageClaims)] + public virtual async Task UpdateClaimAsync(Guid id, IdentityRoleClaimUpdateDto input) + { + var role = await IdentityRoleRepository.GetAsync(id); + var oldClaim = role.FindClaim(new Claim(input.ClaimType, input.ClaimValue)); + if (oldClaim != null) + { + role.RemoveClaim(oldClaim.ToClaim()); + role.AddClaim(GuidGenerator, new Claim(input.ClaimType, input.NewClaimValue)); + + await IdentityRoleRepository.UpdateAsync(role); + + await CurrentUnitOfWork.SaveChangesAsync(); + } + } + + [Authorize(IdentityPermissions.Roles.ManageClaims)] + public virtual async Task DeleteClaimAsync(Guid id, IdentityRoleClaimDeleteDto input) + { + var role = await IdentityRoleRepository.GetAsync(id); + role.RemoveClaim(new Claim(input.ClaimType, input.ClaimValue)); + + await IdentityRoleRepository.UpdateAsync(role); + + await CurrentUnitOfWork.SaveChangesAsync(); + } + + #endregion + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application/Sanhe/Abp/Identity/IdentityUserAppService.cs b/modules/identity/Sanhe.Abp.Identity.Application/Sanhe/Abp/Identity/IdentityUserAppService.cs new file mode 100644 index 0000000..e8d2f33 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application/Sanhe/Abp/Identity/IdentityUserAppService.cs @@ -0,0 +1,151 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Options; +using Sanhe.Abp.Identity.Dto; +using System; +using System.Collections.Generic; +using System.Security.Claims; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Identity; + +namespace Sanhe.Abp.Identity +{ + [Authorize(Volo.Abp.Identity.IdentityPermissions.Users.Default)] + public class IdentityUserAppService : IdentityAppServiceBase, IIdentityUserAppService + { + protected IdentityUserManager UserManager { get; } + protected IOptions IdentityOptions { get; } + public IdentityUserAppService( + IdentityUserManager userManager, + IOptions identityOptions) + { + UserManager = userManager; + IdentityOptions = identityOptions; + } + + #region OrganizationUnit + + + [Authorize(IdentityPermissions.Users.ManageOrganizationUnits)] + public virtual async Task> GetOrganizationUnitsAsync(Guid id) + { + var user = await UserManager.GetByIdAsync(id); + + var organizationUnits = await UserManager.GetOrganizationUnitsAsync(user); + + return new ListResultDto( + ObjectMapper.Map, List>(organizationUnits)); + } + + [Authorize(IdentityPermissions.Users.ManageOrganizationUnits)] + public virtual async Task SetOrganizationUnitsAsync(Guid id, IdentityUserOrganizationUnitUpdateDto input) + { + var user = await UserManager.GetByIdAsync(id); + + await UserManager.SetOrganizationUnitsAsync(user, input.OrganizationUnitIds); + + await CurrentUnitOfWork.SaveChangesAsync(); + } + + [Authorize(IdentityPermissions.Users.ManageOrganizationUnits)] + public virtual async Task RemoveOrganizationUnitsAsync(Guid id, Guid ouId) + { + await UserManager.RemoveFromOrganizationUnitAsync(id, ouId); + + await CurrentUnitOfWork.SaveChangesAsync(); + } + + #endregion + + #region Claim + + public virtual async Task> GetClaimsAsync(Guid id) + { + var user = await UserManager.GetByIdAsync(id); + + return new ListResultDto(ObjectMapper.Map, List>(user.Claims)); + } + + [Authorize(IdentityPermissions.Users.ManageClaims)] + public virtual async Task AddClaimAsync(Guid id, IdentityUserClaimCreateDto input) + { + var user = await UserManager.GetByIdAsync(id); + var claim = new Claim(input.ClaimType, input.ClaimValue); + if (user.FindClaim(claim) != null) + { + throw new UserFriendlyException(L["UserClaimAlreadyExists"]); + } + user.AddClaim(GuidGenerator, claim); + (await UserManager.UpdateAsync(user)).CheckErrors(); + + await CurrentUnitOfWork.SaveChangesAsync(); + } + + [Authorize(IdentityPermissions.Users.ManageClaims)] + public virtual async Task UpdateClaimAsync(Guid id, IdentityUserClaimUpdateDto input) + { + var user = await UserManager.GetByIdAsync(id); + var oldClaim = new Claim(input.ClaimType, input.ClaimValue); + var newClaim = new Claim(input.ClaimType, input.NewClaimValue); + user.ReplaceClaim(oldClaim, newClaim); + (await UserManager.UpdateAsync(user)).CheckErrors(); + + await CurrentUnitOfWork.SaveChangesAsync(); + } + + [Authorize(IdentityPermissions.Users.ManageClaims)] + public virtual async Task DeleteClaimAsync(Guid id, IdentityUserClaimDeleteDto input) + { + var user = await UserManager.GetByIdAsync(id); + user.RemoveClaim(new Claim(input.ClaimType, input.ClaimValue)); + (await UserManager.UpdateAsync(user)).CheckErrors(); + + await CurrentUnitOfWork.SaveChangesAsync(); + } + + #endregion + + [Authorize(Volo.Abp.Identity.IdentityPermissions.Users.Update)] + public virtual async Task ChangeTwoFactorEnabledAsync(Guid id, TwoFactorEnabledDto input) + { + var user = await GetUserAsync(id); + + (await UserManager.SetTwoFactorEnabledWithAccountConfirmedAsync(user, input.Enabled)).CheckErrors(); + + await CurrentUnitOfWork.SaveChangesAsync(); + } + + [Authorize(Volo.Abp.Identity.IdentityPermissions.Users.Update)] + public virtual async Task LockAsync(Guid id, int seconds) + { + var user = await GetUserAsync(id); + //if (!UserManager.SupportsUserLockout) + //{ + // throw new UserFriendlyException(L["Volo.Abp.Identity:UserLockoutNotEnabled"]); + //} + var endDate = new DateTimeOffset(Clock.Now).AddSeconds(seconds); + (await UserManager.SetLockoutEndDateAsync(user, endDate)).CheckErrors(); + + await CurrentUnitOfWork.SaveChangesAsync(); + } + + [Authorize(Volo.Abp.Identity.IdentityPermissions.Users.Update)] + public virtual async Task UnLockAsync(Guid id) + { + var user = await GetUserAsync(id); + (await UserManager.SetLockoutEndDateAsync(user, null)).CheckErrors(); + + await CurrentUnitOfWork.SaveChangesAsync(); + } + + protected virtual async Task GetUserAsync(Guid id) + { + await IdentityOptions.SetAsync(); + var user = await UserManager.GetByIdAsync(id); + + return user; + } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Application/Sanhe/Abp/Identity/OrganizationUnitAppService.cs b/modules/identity/Sanhe.Abp.Identity.Application/Sanhe/Abp/Identity/OrganizationUnitAppService.cs new file mode 100644 index 0000000..1f6016f --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Application/Sanhe/Abp/Identity/OrganizationUnitAppService.cs @@ -0,0 +1,236 @@ +using Microsoft.AspNetCore.Authorization; +using Sanhe.Abp.Identity.Dto; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Identity; +using Volo.Abp.ObjectExtending; + +namespace Sanhe.Abp.Identity +{ + [Authorize(IdentityPermissions.OrganizationUnits.Default)] + public class OrganizationUnitAppService : IdentityAppServiceBase, IOrganizationUnitAppService + { + protected OrganizationUnitManager OrganizationUnitManager { get; } + protected IOrganizationUnitRepository OrganizationUnitRepository { get; } + + protected IdentityUserManager UserManager { get; } + protected IIdentityRoleRepository RoleRepository { get; } + protected IIdentityUserRepository UserRepository { get; } + + public OrganizationUnitAppService( + IdentityUserManager userManager, + IIdentityRoleRepository roleRepository, + IIdentityUserRepository userRepository, + OrganizationUnitManager organizationUnitManager, + IOrganizationUnitRepository organizationUnitRepository) + { + UserManager = userManager; + RoleRepository = roleRepository; + UserRepository = userRepository; + OrganizationUnitManager = organizationUnitManager; + OrganizationUnitRepository = organizationUnitRepository; + + ObjectMapperContext = typeof(AbpIdentityApplicationModule); + } + + [Authorize(IdentityPermissions.OrganizationUnits.Create)] + public virtual async Task CreateAsync(OrganizationUnitCreateDto input) + { + var organizationUnit = new OrganizationUnit( + GuidGenerator.Create(), input.DisplayName, input.ParentId, CurrentTenant.Id) + { + CreationTime = Clock.Now + }; + input.MapExtraPropertiesTo(organizationUnit); + + await OrganizationUnitManager.CreateAsync(organizationUnit); + await CurrentUnitOfWork.SaveChangesAsync(); + + return ObjectMapper.Map(organizationUnit); + } + + [Authorize(IdentityPermissions.OrganizationUnits.Delete)] + public virtual async Task DeleteAsync(Guid id) + { + var organizationUnit = await OrganizationUnitRepository.FindAsync(id); + if (organizationUnit == null) + { + return; + } + await OrganizationUnitManager.DeleteAsync(id); + } + + public virtual async Task> GetRootAsync() + { + var rootorganizationUnits = await OrganizationUnitManager.FindChildrenAsync(null, recursive: false); + + return new ListResultDto( + ObjectMapper.Map, List>(rootorganizationUnits)); + } + + public virtual async Task> FindChildrenAsync(OrganizationUnitGetChildrenDto input) + { + var organizationUnitChildren = await OrganizationUnitManager.FindChildrenAsync(input.Id, input.Recursive); + + return new ListResultDto( + ObjectMapper.Map, List>(organizationUnitChildren)); + } + + public virtual async Task GetAsync(Guid id) + { + var organizationUnit = await OrganizationUnitRepository.FindAsync(id); + + return ObjectMapper.Map(organizationUnit); + } + + public virtual async Task GetLastChildOrNullAsync(Guid? parentId) + { + var organizationUnitLastChildren = await OrganizationUnitManager.GetLastChildOrNullAsync(parentId); + + return ObjectMapper.Map(organizationUnitLastChildren); + } + + public virtual async Task> GetAllListAsync() + { + var organizationUnits = await OrganizationUnitRepository.GetListAsync(false); + + return new ListResultDto( + ObjectMapper.Map, List>(organizationUnits)); + } + + public virtual async Task> GetListAsync(OrganizationUnitGetByPagedDto input) + { + var organizationUnitCount = await OrganizationUnitRepository.GetCountAsync(); + var organizationUnits = await OrganizationUnitRepository + .GetListAsync(input.Sorting, input.MaxResultCount, input.SkipCount, false); + + return new PagedResultDto(organizationUnitCount, + ObjectMapper.Map, List>(organizationUnits)); + } + + [Authorize(IdentityPermissions.OrganizationUnits.ManageRoles)] + public virtual async Task> GetRoleNamesAsync(Guid id) + { + var inOrignizationUnitRoleNames = await UserRepository.GetRoleNamesInOrganizationUnitAsync(id); + return new ListResultDto(inOrignizationUnitRoleNames); + } + + [Authorize(IdentityPermissions.OrganizationUnits.ManageRoles)] + public virtual async Task> GetUnaddedRolesAsync(Guid id, OrganizationUnitGetUnaddedRoleByPagedDto input) + { + var organizationUnit = await OrganizationUnitRepository.GetAsync(id); + + var organizationUnitRoleCount = await OrganizationUnitRepository + .GetUnaddedRolesCountAsync(organizationUnit, input.Filter); + + var organizationUnitRoles = await OrganizationUnitRepository + .GetUnaddedRolesAsync(organizationUnit, + input.Sorting, input.MaxResultCount, + input.SkipCount, input.Filter); + + return new PagedResultDto(organizationUnitRoleCount, + ObjectMapper.Map, List>(organizationUnitRoles)); + } + + [Authorize(IdentityPermissions.OrganizationUnits.ManageRoles)] + public virtual async Task> GetRolesAsync(Guid id, PagedAndSortedResultRequestDto input) + { + var organizationUnit = await OrganizationUnitRepository.GetAsync(id); + + var organizationUnitRoleCount = await OrganizationUnitRepository + .GetRolesCountAsync(organizationUnit); + + var organizationUnitRoles = await OrganizationUnitRepository + .GetRolesAsync(organizationUnit, + input.Sorting, input.MaxResultCount, + input.SkipCount); + + return new PagedResultDto(organizationUnitRoleCount, + ObjectMapper.Map, List>(organizationUnitRoles)); + } + + + [Authorize(IdentityPermissions.OrganizationUnits.ManageUsers)] + public virtual async Task> GetUnaddedUsersAsync(Guid id, OrganizationUnitGetUnaddedUserByPagedDto input) + { + var organizationUnit = await OrganizationUnitRepository.GetAsync(id); + + var organizationUnitUserCount = await OrganizationUnitRepository + .GetUnaddedUsersCountAsync(organizationUnit, input.Filter); + var organizationUnitUsers = await OrganizationUnitRepository + .GetUnaddedUsersAsync(organizationUnit, + input.Sorting, input.MaxResultCount, + input.SkipCount, input.Filter); + + return new PagedResultDto(organizationUnitUserCount, + ObjectMapper.Map, List>(organizationUnitUsers)); + } + + [Authorize(IdentityPermissions.OrganizationUnits.ManageUsers)] + public virtual async Task> GetUsersAsync(Guid id, GetIdentityUsersInput input) + { + var organizationUnit = await OrganizationUnitRepository.GetAsync(id); + + var organizationUnitUserCount = await OrganizationUnitRepository + .GetMembersCountAsync(organizationUnit, input.Filter); + var organizationUnitUsers = await OrganizationUnitRepository + .GetMembersAsync(organizationUnit, + input.Sorting, input.MaxResultCount, + input.SkipCount, input.Filter); + + return new PagedResultDto(organizationUnitUserCount, + ObjectMapper.Map, List>(organizationUnitUsers)); + } + + [Authorize(IdentityPermissions.OrganizationUnits.Update)] + public virtual async Task MoveAsync(Guid id, OrganizationUnitMoveDto input) + { + await OrganizationUnitManager.MoveAsync(id, input.ParentId); + } + + [Authorize(IdentityPermissions.OrganizationUnits.Update)] + public virtual async Task UpdateAsync(Guid id, OrganizationUnitUpdateDto input) + { + var organizationUnit = await OrganizationUnitRepository.GetAsync(id); + organizationUnit.DisplayName = input.DisplayName; + input.MapExtraPropertiesTo(organizationUnit); + + await OrganizationUnitManager.UpdateAsync(organizationUnit); + await CurrentUnitOfWork.SaveChangesAsync(); + + return ObjectMapper.Map(organizationUnit); + } + + [Authorize(IdentityPermissions.OrganizationUnits.ManageUsers)] + public virtual async Task AddUsersAsync(Guid id, OrganizationUnitAddUserDto input) + { + var organizationUnit = await OrganizationUnitRepository.GetAsync(id); + var users = await UserRepository.GetListByIdListAsync(input.UserIds, includeDetails: true); + + // 调用内部方法设置用户组织机构 + foreach (var user in users) + { + await UserManager.AddToOrganizationUnitAsync(user, organizationUnit); + } + + await CurrentUnitOfWork.SaveChangesAsync(); + } + + [Authorize(IdentityPermissions.OrganizationUnits.ManageRoles)] + public virtual async Task AddRolesAsync(Guid id, OrganizationUnitAddRoleDto input) + { + var organizationUnit = await OrganizationUnitRepository.GetAsync(id); + + var roles = await RoleRepository.GetListByIdListAsync(input.RoleIds, includeDetails: true); + + foreach (var role in roles) + { + await OrganizationUnitManager.AddRoleToOrganizationUnitAsync(role, organizationUnit); + } + + await CurrentUnitOfWork.SaveChangesAsync(); + } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Domain.Shared/FodyWeavers.xml b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/FodyWeavers.xml new file mode 100644 index 0000000..1715698 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe.Abp.Identity.Domain.Shared.csproj b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe.Abp.Identity.Domain.Shared.csproj new file mode 100644 index 0000000..ccce677 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe.Abp.Identity.Domain.Shared.csproj @@ -0,0 +1,27 @@ + + + + + + + + netstandard2.0 + + + + + + + + + + + + + + + + + + + diff --git a/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/AbpIdentityDomainSharedModule.cs b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/AbpIdentityDomainSharedModule.cs new file mode 100644 index 0000000..23e5796 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/AbpIdentityDomainSharedModule.cs @@ -0,0 +1,26 @@ +using Volo.Abp.Identity.Localization; +using Volo.Abp.Localization; +using Volo.Abp.Modularity; +using Volo.Abp.VirtualFileSystem; + +namespace Sanhe.Abp.Identity +{ + [DependsOn(typeof(Volo.Abp.Identity.AbpIdentityDomainSharedModule))] + public class AbpIdentityDomainSharedModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + + Configure(options => + { + options.Resources + .Get() + .AddVirtualJson("/Sanhe/Abp/Identity/Localization"); + }); + } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/IUserSecurityCodeSender.cs b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/IUserSecurityCodeSender.cs new file mode 100644 index 0000000..b287ce5 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/IUserSecurityCodeSender.cs @@ -0,0 +1,36 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace Sanhe.Abp.Identity +{ + public interface IUserSecurityCodeSender + { + /// + /// 发送手机确认码 + /// + /// 手机号 + /// 令牌 + /// 模板号 + /// + /// + Task SendPhoneConfirmedCodeAsync( + string phone, + string token, + string template, // 传递模板号 + CancellationToken cancellation = default); + + /// + /// 发送邮箱确认码 + /// + /// 用户名 + /// 邮箱 + /// 令牌 + /// + /// + Task SendEmailConfirmedCodeAsync( + string userName, + string email, + string token, + CancellationToken cancellation = default); + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/IdentityConsts.cs b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/IdentityConsts.cs new file mode 100644 index 0000000..fe924d5 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/IdentityConsts.cs @@ -0,0 +1,15 @@ +namespace Sanhe.Abp.Identity +{ + public static class IdentityConsts + { + public static class ClaimType + { + public static class Avatar + { + public static string Name { get; set; } = "avatarUrl"; + public static string DisplayName { get; set; } = "Your avatar url"; + public static string Description { get; set; } = "Your avatar url"; + } + } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/IdentityErrorCodes.cs b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/IdentityErrorCodes.cs new file mode 100644 index 0000000..9ab046e --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/IdentityErrorCodes.cs @@ -0,0 +1,26 @@ +namespace Sanhe.Abp.Identity +{ + public static class IdentityErrorCodes + { + /// + /// 无法变更静态声明类型 + /// + public const string StaticClaimTypeChange = "Volo.Abp.Identity:020005"; + /// + /// 无法删除静态声明类型 + /// + public const string StaticClaimTypeDeletion = "Volo.Abp.Identity:020006"; + /// + /// 手机号码已被使用 + /// + public const string DuplicatePhoneNumber = "Volo.Abp.Identity:020007"; + /// + /// 你不能修改你的手机绑定信息 + /// + public const string UsersCanNotChangePhoneNumber = "Volo.Abp.Identity:020008"; + /// + /// 你不能修改你的邮件绑定信息 + /// + public const string UsersCanNotChangeEmailAddress = "Volo.Abp.Identity:020009"; + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/IdentityException.cs b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/IdentityException.cs new file mode 100644 index 0000000..91b89c5 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/IdentityException.cs @@ -0,0 +1,38 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Runtime.Serialization; +using Volo.Abp; +using Volo.Abp.Logging; + +namespace Sanhe.Abp.Identity +{ + public class IdentityException : BusinessException, IExceptionWithSelfLogging + { + public IdentityException( + SerializationInfo serializationInfo, + StreamingContext context) + : base(serializationInfo, context) + { + } + + public IdentityException( + string code = null, + string message = null, + string details = null, + Exception innerException = null, + LogLevel logLevel = LogLevel.Warning) + : base(code, message, details, innerException, logLevel) + { + } + + public virtual void Log(ILogger logger) + { + logger.Log( + LogLevel, + "An id error occurred,code: {0}, Message: {1}, Details: {2}", + Code, + Message, + Details); + } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/Localization/en.json b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/Localization/en.json new file mode 100644 index 0000000..f451ba5 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/Localization/en.json @@ -0,0 +1,64 @@ +{ + "culture": "en", + "texts": { + "Permission:OrganizationUnitManagement": "Organization unit management", + "Permission:ManageRoles": "Management roles", + "Permission:ManageUsers": "Management users", + "Permission:ManageClaims": "Management claims", + "Permission:ManageOrganizationUnits": "Management organization units", + "Permission:IdentityClaimTypeManagement": "Management claim types", + "OrganizationUnit:Tree": "Organization tree", + "OrganizationUnit:New": "Add New", + "OrganizationUnit:Members": "Organization Members", + "OrganizationUnit:AddRoot": "Add Root", + "OrganizationUnit:AddChildren": "Add Children", + "OrganizationUnit:AddMember": "Add Member", + "OrganizationUnit:AddRole": "Add Role", + "OrganizationUnit:DisplayName": "Display Name", + "OrganizationUnit:WillDelete": "Organization: {0} will be deleted", + "OrganizationUnit:AreYouSureRemoveUser": "Are you sure you want to delete user {0} from your organization?", + "OrganizationUnit:AreYouSureRemoveRole": "Are you sure you want to remove the role {0} from the organization?", + "OrganizationUnit:SelectUsers": "Select Users", + "OrganizationUnit:SelectRoles": "Select Roles", + "IdentityClaimTypeAlreadyExists": "The identity claim type {0} already exists!", + "UserClaimAlreadyExists": "User claim with the same parameters have been added!", + "RoleClaimAlreadyExists": "Role claim with the same parameters has been added!", + "DisplayName:ClaimType": "Type", + "DisplayName:ClaimValue": "Value", + "ClaimSubject": "Claim - {0}", + "RoleSubject": "Role - {0}", + "AddClaim": "Add claim", + "UpdateClaim": "Update claim", + "DeleteClaim": "Delete claim", + "WillDeleteClaim": "Pending deletion claim type: {0}", + "ManageClaim": "Management claim", + "IdentityClaim:New": "New claim", + "IdentityClaim:Name": "Name", + "IdentityClaim:Required": "Required", + "IdentityClaim:IsStatic": "Is static", + "IdentityClaim:Regex": "Regex", + "IdentityClaim:RegexDescription": "Regex description", + "IdentityClaim:Description": "Description", + "IdentityClaim:ValueType": "Value type", + "Volo.Abp.Identity:020005": "The static claim type cannot be changed!", + "Volo.Abp.Identity:020006": "Unable to delete static claim type!", + "Volo.Abp.Identity:020007": "The phone number is already tied to another user!", + "Volo.Abp.Identity:020008": "You can't modify your phone's binding information!", + "Volo.Abp.Identity:020009": "You cannot modify your email binding information!", + "Volo.Abp.Identity:DuplicatePhoneNumber": "Phone number '{0}' is already taken.", + "DisplayName:Abp.Identity.User.SmsNewUserRegister": "Register sms template", + "Description:Abp.Identity.User.SmsNewUserRegister": "When the user registers, he/she should send the template number of the SMS verification code and fill in the template number of the corresponding cloud platform registration", + "DisplayName:Abp.Identity.User.SmsUserSignin": "Signin sms template", + "Description:Abp.Identity.User.SmsUserSignin": "When the user logs in, he/she should send the template number of the SMS verification code and fill in the template number of the corresponding cloud platform registration", + "DisplayName:Abp.Identity.User.SmsResetPassword": "Reset password sms template", + "Description:Abp.Identity.User.SmsResetPassword": "When the user resets the password, he/she sends the template number of SMS verification code and fills in the template number registered on the cloud platform", + "DisplayName:Abp.Identity.User.SmsPhoneNumberConfirmed": "Phone number confirmation template", + "Description:Abp.Identity.User.SmsPhoneNumberConfirmed": "The user confirms the mobile phone verification code template", + "DisplayName:Abp.Identity.User.SmsRepeatInterval": "SMS verification code validity(min)", + "Description:Abp.Identity.User.SmsRepeatInterval": "The valid time for the user to send SMS verification code, unit m, default 3min", + "DisplayName:SmsVerifyCode": "SMS verification code", + "DisplayName:EmailVerifyCode": "Mail verification code", + "DisplayName:WeChatCode": "Wechat login code", + "SendRepeatSmsVerifyCode": "Phone verification code cannot be sent repeatedly within {0} minutes!" + } +} \ No newline at end of file diff --git a/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/Localization/zh-Hans.json b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/Localization/zh-Hans.json new file mode 100644 index 0000000..04ed3d9 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/Localization/zh-Hans.json @@ -0,0 +1,64 @@ +{ + "culture": "zh-Hans", + "texts": { + "Permission:OrganizationUnitManagement": "组织机构管理", + "Permission:ManageRoles": "管理角色", + "Permission:ManageUsers": "管理用户", + "Permission:ManageClaims": "管理声明", + "Permission:ManageOrganizationUnits": "管理组织机构", + "Permission:IdentityClaimTypeManagement": "管理声明类型", + "OrganizationUnit:Tree": "组织机构树", + "OrganizationUnit:New": "新组织结构", + "OrganizationUnit:Members": "机构成员", + "OrganizationUnit:AddRoot": "添加根机构", + "OrganizationUnit:AddChildren": "添加子机构", + "OrganizationUnit:AddMember": "添加成员", + "OrganizationUnit:AddRole": "添加角色", + "OrganizationUnit:DisplayName": "显示名称", + "OrganizationUnit:WillDelete": "组织机构: {0} 将被删除", + "OrganizationUnit:AreYouSureRemoveUser": "你确定要从组织机构中删除用户 {0} 吗?", + "OrganizationUnit:AreYouSureRemoveRole": "你确定要从组织机构中删除角色 {0} 吗?", + "OrganizationUnit:SelectUsers": "选择用户", + "OrganizationUnit:SelectRoles": "选择角色", + "IdentityClaimTypeAlreadyExists": "声明类型 {0} 已经存在!", + "UserClaimAlreadyExists": "已经添加相同参数的用户声明!", + "RoleClaimAlreadyExists": "已经添加相同参数的角色声明", + "DisplayName:ClaimType": "声明类型", + "DisplayName:ClaimValue": "声明值", + "ClaimSubject": "声明 - {0}", + "RoleSubject": "角色 - {0}", + "AddClaim": "添加声明", + "UpdateClaim": "变更声明", + "DeleteClaim": "删除声明", + "WillDeleteClaim": "声明类型: {0} 将被删除", + "ManageClaim": "管理声明", + "IdentityClaim:New": "新声明类型", + "IdentityClaim:Name": "名称", + "IdentityClaim:Required": "是否必须", + "IdentityClaim:IsStatic": "是否静态", + "IdentityClaim:Regex": "正则", + "IdentityClaim:RegexDescription": "正则描述", + "IdentityClaim:Description": "描述", + "IdentityClaim:ValueType": "值类型", + "Volo.Abp.Identity:020005": "无法变更静态声明类型!", + "Volo.Abp.Identity:020006": "无法删除静态声明类型!", + "Volo.Abp.Identity:020007": "手机号码已被其他用户绑定!", + "Volo.Abp.Identity:020008": "你不能修改你的手机绑定信息!", + "Volo.Abp.Identity:020009": "你不能修改你的邮件绑定信息!", + "Volo.Abp.Identity:DuplicatePhoneNumber": "手机号 '{0}' 已存在.", + "DisplayName:Abp.Identity.User.SmsNewUserRegister": "新用户注册模板", + "Description:Abp.Identity.User.SmsNewUserRegister": "新用户通过手机注册账号验证码模板", + "DisplayName:Abp.Identity.User.SmsUserSignin": "用户登录模板", + "Description:Abp.Identity.User.SmsUserSignin": "用户通过手机登录验证码模板", + "DisplayName:Abp.Identity.User.SmsResetPassword": "密码找回模板", + "Description:Abp.Identity.User.SmsResetPassword": "用户通过手机找回密码验证码模板", + "DisplayName:Abp.Identity.User.SmsPhoneNumberConfirmed": "手机确认模板", + "Description:Abp.Identity.User.SmsPhoneNumberConfirmed": "用户确认手机号验证码模板", + "DisplayName:Abp.Identity.User.SmsRepeatInterval": "重复发送间隔时间(min)", + "Description:Abp.Identity.User.SmsRepeatInterval": "验证码重复发送的最小时间差,单位为分", + "DisplayName:SmsVerifyCode": "短信验证码", + "DisplayName:EmailVerifyCode": "邮件验证码", + "DisplayName:WeChatCode": "微信登录凭证", + "SendRepeatSmsVerifyCode": "手机验证码不能在 {0} 分钟内重复发送!" + } +} \ No newline at end of file diff --git a/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/Security/DefaultTotpService.cs b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/Security/DefaultTotpService.cs new file mode 100644 index 0000000..343ef3e --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/Security/DefaultTotpService.cs @@ -0,0 +1,121 @@ +using System; +using System.Diagnostics; +using System.Net; +using System.Security.Cryptography; +using System.Text; +using Volo.Abp.DependencyInjection; + +namespace Sanhe.Abp.Identity.Security +{ + /// + /// 微软的实现 + /// See: Microsoft.AspNetCore.Identity.Rfc6238AuthenticationService + /// + internal class DefaultTotpService : ITotpService, ISingletonDependency + { + private static readonly TimeSpan _timestep = TimeSpan.FromMinutes(3); + private static readonly Encoding _encoding = new UTF8Encoding(false, true); +#if NETSTANDARD2_0 + private static readonly DateTime _unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + private static readonly RandomNumberGenerator _rng = RandomNumberGenerator.Create(); +#endif + + // Generates a new 80-bit security token + public static byte[] GenerateRandomKey() + { + var bytes = new byte[20]; +#if NETSTANDARD2_0 + _rng.GetBytes(bytes); +#else + RandomNumberGenerator.Fill(bytes); +#endif + return bytes; + } + + internal static int ComputeTotp(HashAlgorithm hashAlgorithm, ulong timestepNumber, string modifier) + { + // # of 0's = length of pin + const int Mod = 1000000; + + // See https://tools.ietf.org/html/rfc4226 + // We can add an optional modifier + var timestepAsBytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((long)timestepNumber)); + var hash = hashAlgorithm.ComputeHash(ApplyModifier(timestepAsBytes, modifier)); + + // Generate DT string + var offset = hash[hash.Length - 1] & 0xf; + Debug.Assert(offset + 4 < hash.Length); + var binaryCode = (hash[offset] & 0x7f) << 24 + | (hash[offset + 1] & 0xff) << 16 + | (hash[offset + 2] & 0xff) << 8 + | hash[offset + 3] & 0xff; + + return binaryCode % Mod; + } + + private static byte[] ApplyModifier(byte[] input, string modifier) + { + if (string.IsNullOrEmpty(modifier)) + { + return input; + } + + var modifierBytes = _encoding.GetBytes(modifier); + var combined = new byte[checked(input.Length + modifierBytes.Length)]; + Buffer.BlockCopy(input, 0, combined, 0, input.Length); + Buffer.BlockCopy(modifierBytes, 0, combined, input.Length, modifierBytes.Length); + return combined; + } + + // More info: https://tools.ietf.org/html/rfc6238#section-4 + private static ulong GetCurrentTimeStepNumber() + { +#if NETSTANDARD2_0 + var delta = DateTime.UtcNow - _unixEpoch; +#else + var delta = DateTimeOffset.UtcNow - DateTimeOffset.UnixEpoch; +#endif + return (ulong)(delta.Ticks / _timestep.Ticks); + } + + public int GenerateCode(byte[] securityToken, string modifier = null) + { + if (securityToken == null) + { + throw new ArgumentNullException(nameof(securityToken)); + } + + // Allow a variance of no greater than 9 minutes in either direction + var currentTimeStep = GetCurrentTimeStepNumber(); + using (var hashAlgorithm = new HMACSHA1(securityToken)) + { + return ComputeTotp(hashAlgorithm, currentTimeStep, modifier); + } + } + + public bool ValidateCode(byte[] securityToken, int code, string modifier = null) + { + if (securityToken == null) + { + throw new ArgumentNullException(nameof(securityToken)); + } + + // Allow a variance of no greater than 9 minutes in either direction + var currentTimeStep = GetCurrentTimeStepNumber(); + using (var hashAlgorithm = new HMACSHA1(securityToken)) + { + for (var i = -2; i <= 2; i++) + { + var computedTotp = ComputeTotp(hashAlgorithm, (ulong)((long)currentTimeStep + i), modifier); + if (computedTotp == code) + { + return true; + } + } + } + + // No match + return false; + } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/Security/ITotpService.cs b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/Security/ITotpService.cs new file mode 100644 index 0000000..f14c8c8 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/Security/ITotpService.cs @@ -0,0 +1,25 @@ +namespace Sanhe.Abp.Identity.Security +{ + /// + /// totp算法服务 + /// + public interface ITotpService + { + /// + /// 生成 + /// + /// + /// + /// + int GenerateCode(byte[] securityToken, string modifier = null); + + /// + /// 验证 + /// + /// + /// + /// + /// + bool ValidateCode(byte[] securityToken, int code, string modifier = null); + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/Settings/IdentitySettingDefinitionProvider.cs b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/Settings/IdentitySettingDefinitionProvider.cs new file mode 100644 index 0000000..7d027e7 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/Settings/IdentitySettingDefinitionProvider.cs @@ -0,0 +1,75 @@ +using Volo.Abp.Identity.Localization; +using Volo.Abp.Localization; +using Volo.Abp.Settings; + +namespace Sanhe.Abp.Identity.Settings +{ + public class IdentitySettingDefinitionProvider : SettingDefinitionProvider + { + public override void Define(ISettingDefinitionContext context) + { + context.Add( + new SettingDefinition( + name: IdentitySettingNames.User.SmsNewUserRegister, + defaultValue: "", + displayName: L("DisplayName:Abp.Identity.User.SmsNewUserRegister"), + description: L("Description:Abp.Identity.User.SmsNewUserRegister"), + isVisibleToClients: true) + .WithProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName), + new SettingDefinition( + name: IdentitySettingNames.User.SmsUserSignin, + defaultValue: "", + displayName: L("DisplayName:Abp.Identity.User.SmsUserSignin"), + description: L("Description:Abp.Identity.User.SmsUserSignin"), + isVisibleToClients: true) + .WithProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName), + new SettingDefinition( + name: IdentitySettingNames.User.SmsResetPassword, + defaultValue: "", + displayName: L("DisplayName:Abp.Identity.User.SmsResetPassword"), + description: L("Description:Abp.Identity.User.SmsResetPassword"), + isVisibleToClients: true) + .WithProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName), + new SettingDefinition( + name: IdentitySettingNames.User.SmsPhoneNumberConfirmed, + defaultValue: "", + displayName: L("DisplayName:Abp.Identity.User.SmsPhoneNumberConfirmed"), + description: L("Description:Abp.Identity.User.SmsPhoneNumberConfirmed"), + isVisibleToClients: true) + .WithProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName), + new SettingDefinition( + name: IdentitySettingNames.User.SmsRepeatInterval, + defaultValue: "5", + displayName: L("DisplayName:Abp.Identity.User.SmsRepeatInterval"), + description: L("Description:Abp.Identity.User.SmsRepeatInterval"), + isVisibleToClients: true) + .WithProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName) + ); + } + + private static LocalizableString L(string name) + { + return LocalizableString.Create(name); + } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/Settings/IdentitySettingNames.cs b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/Settings/IdentitySettingNames.cs new file mode 100644 index 0000000..f327426 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Domain.Shared/Sanhe/Abp/Identity/Settings/IdentitySettingNames.cs @@ -0,0 +1,32 @@ +namespace Sanhe.Abp.Identity.Settings +{ + public static class IdentitySettingNames + { + private const string Prefix = "Abp.Identity"; + + public static class User + { + private const string UserPrefix = Prefix + ".User"; + /// + /// 用户手机验证短信模板 + /// + public const string SmsPhoneNumberConfirmed = UserPrefix + ".SmsPhoneNumberConfirmed"; + /// + /// 用户注册短信验证码模板号 + /// + public const string SmsNewUserRegister = UserPrefix + ".SmsNewUserRegister"; + /// + /// 用户登录短信验证码模板号 + /// + public const string SmsUserSignin = UserPrefix + ".SmsUserSignin"; + /// + /// 用户重置密码短信验证码模板号 + /// + public const string SmsResetPassword = UserPrefix + ".SmsResetPassword"; + /// + /// 验证码重复间隔时间 + /// + public const string SmsRepeatInterval = UserPrefix + ".SmsRepeatInterval"; + } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Domain/FodyWeavers.xml b/modules/identity/Sanhe.Abp.Identity.Domain/FodyWeavers.xml new file mode 100644 index 0000000..1715698 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Domain/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/identity/Sanhe.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/IdentityUserManagerExtensions.cs b/modules/identity/Sanhe.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/IdentityUserManagerExtensions.cs new file mode 100644 index 0000000..5b817d8 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/IdentityUserManagerExtensions.cs @@ -0,0 +1,39 @@ +using JetBrains.Annotations; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Identity; + +namespace Microsoft.AspNetCore.Identity +{ + public static class IdentityUserManagerExtensions + { + public static async Task SetTwoFactorEnabledWithAccountConfirmedAsync( + [NotNull] this UserManager userManager, + [NotNull] TUser user, + bool enabled) + where TUser : class + { + Check.NotNull(userManager, nameof(userManager)); + Check.NotNull(user, nameof(user)); + + if (enabled) + { + var phoneNumberConfirmed = await userManager.IsPhoneNumberConfirmedAsync(user); + var emailAddressConfirmed = await userManager.IsEmailConfirmedAsync(user); + // 如果其中一个安全选项未确认,无法启用双因素验证 + if (!phoneNumberConfirmed && !emailAddressConfirmed) + { + // TODO: 返回标准的 IdentityResult + //var error = new IdentityError(); + //return IdentityResult.Failed(error); + + throw new Sanhe.Abp.Identity.IdentityException( + IdentityErrorCodes.CanNotChangeTwoFactor, + details: phoneNumberConfirmed ? "phone number not confirmed" : "email address not confirmed"); + } + } + + return await userManager.SetTwoFactorEnabledAsync(user, enabled); + } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/PhoneNumberUserValidator.cs b/modules/identity/Sanhe.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/PhoneNumberUserValidator.cs new file mode 100644 index 0000000..dbb8dab --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/PhoneNumberUserValidator.cs @@ -0,0 +1,58 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Localization; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Identity; +using Volo.Abp.Identity.Localization; +using IIdentityUserRepository = Sanhe.Abp.Identity.IIdentityUserRepository; + +namespace Microsoft.AspNetCore.Identity +{ + [Dependency(ServiceLifetime.Scoped, ReplaceServices = true)] + [ExposeServices(typeof(IUserValidator))] + public class PhoneNumberUserValidator : UserValidator + { + private readonly IStringLocalizer _stringLocalizer; + private readonly IIdentityUserRepository _userRepository; + + public PhoneNumberUserValidator( + IIdentityUserRepository userRepository, + IStringLocalizer stringLocalizer) + { + _userRepository = userRepository; + _stringLocalizer = stringLocalizer; + } + + public async override Task ValidateAsync(UserManager manager, IdentityUser user) + { + var errors = new List(); + await ValidatePhoneNumberAsync(manager, user, errors); + + return (errors.Count > 0) + ? IdentityResult.Failed(errors.ToArray()) + : await base.ValidateAsync(manager, user); + } + + protected async virtual Task ValidatePhoneNumberAsync(UserManager manager, IdentityUser user, ICollection errors) + { + var phoneNumber = await manager.GetPhoneNumberAsync(user); + if (phoneNumber.IsNullOrWhiteSpace()) + { + return; + } + var findUser = await _userRepository.FindByPhoneNumberAsync(phoneNumber, false); + if (findUser != null && !findUser.Id.Equals(user.Id)) + { + //errors.Add(new IdentityError + //{ + // Code = "DuplicatePhoneNumber", + // Description = _stringLocalizer["DuplicatePhoneNumber", phoneNumber] + //}); + throw new UserFriendlyException(_stringLocalizer["Volo.Abp.Identity:DuplicatePhoneNumber", phoneNumber]); + } + } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Domain/Sanhe.Abp.Identity.Domain.csproj b/modules/identity/Sanhe.Abp.Identity.Domain/Sanhe.Abp.Identity.Domain.csproj new file mode 100644 index 0000000..5b90c19 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Domain/Sanhe.Abp.Identity.Domain.csproj @@ -0,0 +1,18 @@ + + + + + + + netstandard2.0 + + + + + + + + + + + diff --git a/modules/identity/Sanhe.Abp.Identity.Domain/Sanhe/Abp/Identity/AbpIdentityDomainModule.cs b/modules/identity/Sanhe.Abp.Identity.Domain/Sanhe/Abp/Identity/AbpIdentityDomainModule.cs new file mode 100644 index 0000000..2477272 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Domain/Sanhe/Abp/Identity/AbpIdentityDomainModule.cs @@ -0,0 +1,11 @@ +using Volo.Abp.Modularity; + +namespace Sanhe.Abp.Identity +{ + [DependsOn( + typeof(AbpIdentityDomainSharedModule), + typeof(Volo.Abp.Identity.AbpIdentityDomainModule))] + public class AbpIdentityDomainModule : AbpModule + { + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Domain/Sanhe/Abp/Identity/IIdentityRoleRepository.cs b/modules/identity/Sanhe.Abp.Identity.Domain/Sanhe/Abp/Identity/IIdentityRoleRepository.cs new file mode 100644 index 0000000..2cdf4c6 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Domain/Sanhe/Abp/Identity/IIdentityRoleRepository.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Identity; + +namespace Sanhe.Abp.Identity +{ + public interface IIdentityRoleRepository : Volo.Abp.Identity.IIdentityRoleRepository + { + Task> GetListByIdListAsync( + List roleIds, + bool includeDetails = false, + CancellationToken cancellationToken = default); + + Task> GetOrganizationUnitsAsync( + Guid id, + bool includeDetails = false, + CancellationToken cancellationToken = default); + + Task> GetOrganizationUnitsAsync( + IEnumerable roleNames, + bool includeDetails = false, + CancellationToken cancellationToken = default); + + Task> GetRolesInOrganizationUnitAsync( + Guid organizationUnitId, + CancellationToken cancellationToken = default); + + Task> GetRolesInOrganizationsListAsync( + List organizationUnitIds, + CancellationToken cancellationToken = default); + + Task> GetRolesInOrganizationUnitWithChildrenAsync( + string code, + CancellationToken cancellationToken = default); + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Domain/Sanhe/Abp/Identity/IIdentityUserRepository.cs b/modules/identity/Sanhe.Abp.Identity.Domain/Sanhe/Abp/Identity/IIdentityUserRepository.cs new file mode 100644 index 0000000..8c24f9c --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Domain/Sanhe/Abp/Identity/IIdentityUserRepository.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Identity; + +namespace Sanhe.Abp.Identity +{ + public interface IIdentityUserRepository : Volo.Abp.Identity.IIdentityUserRepository + { + /// + /// 手机号是否已被使用 + /// + /// + /// + /// + Task IsPhoneNumberUedAsync( + string phoneNumber, + CancellationToken cancellationToken = default); + + /// + /// 手机号是否已确认(绑定) + /// + /// + /// + /// + Task IsPhoneNumberConfirmedAsync( + string phoneNumber, + CancellationToken cancellationToken = default); + + /// + /// 邮件地址是否已确认(绑定) + /// + /// + /// + /// + Task IsNormalizedEmailConfirmedAsync( + string normalizedEmail, + CancellationToken cancellationToken = default); + + /// + /// 通过手机号查询用户 + /// + /// 手机号码 + /// 是否已确认过 + /// + /// + /// + Task FindByPhoneNumberAsync( + string phoneNumber, + bool isConfirmed = true, + bool includeDetails = false, + CancellationToken cancellationToken = default); + + /// + /// 通过用户主键列表获取用户 + /// + /// + /// + /// + /// + Task> GetListByIdListAsync( + List userIds, + bool includeDetails = false, + CancellationToken cancellationToken = default); + + /// + /// 获取用户所有的组织机构列表 + /// + /// + /// + /// + /// + /// + /// + /// + Task> GetOrganizationUnitsAsync( + Guid userId, + string filter = null, + bool includeDetails = false, + int skipCount = 1, + int maxResultCount = 10, + CancellationToken cancellationToken = default); + + /// + /// + /// + /// + /// + /// + /// + Task GetUsersInOrganizationUnitCountAsync( + Guid organizationUnitId, + string filter = null, + CancellationToken cancellationToken = default); + + Task> GetUsersInOrganizationUnitAsync( + Guid organizationUnitId, + string filter = null, + int skipCount = 1, + int maxResultCount = 10, + CancellationToken cancellationToken = default); + + Task GetUsersInOrganizationsListCountAsync( + List organizationUnitIds, + string filter = null, + CancellationToken cancellationToken = default); + + Task> GetUsersInOrganizationsListAsync( + List organizationUnitIds, + string filter = null, + int skipCount = 1, + int maxResultCount = 10, + CancellationToken cancellationToken = default); + + Task GetUsersInOrganizationUnitWithChildrenCountAsync( + string code, + string filter = null, + CancellationToken cancellationToken = default); + + Task> GetUsersInOrganizationUnitWithChildrenAsync( + string code, + string filter = null, + int skipCount = 1, + int maxResultCount = 10, + CancellationToken cancellationToken = default); + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.Domain/Sanhe/Abp/Identity/SmsSecurityTokenCacheItem.cs b/modules/identity/Sanhe.Abp.Identity.Domain/Sanhe/Abp/Identity/SmsSecurityTokenCacheItem.cs new file mode 100644 index 0000000..08f85c0 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.Domain/Sanhe/Abp/Identity/SmsSecurityTokenCacheItem.cs @@ -0,0 +1,39 @@ +namespace Sanhe.Abp.Identity +{ + /// + /// 短信安全令牌验证缓存 + /// + public class SmsSecurityTokenCacheItem + { + /// + /// 用于验证的Token + /// + public string Token { get; set; } + /// + /// 用于验证的安全令牌 + /// + public string SecurityToken { get; set; } + + public SmsSecurityTokenCacheItem() + { + + } + + public SmsSecurityTokenCacheItem(string token, string securityToken) + { + Token = token; + SecurityToken = securityToken; + } + + /// + /// 生成查询Key + /// + /// 手机号 + /// 安全令牌用途 + /// + public static string CalculateCacheKey(string phoneNumber, string purpose) + { + return "Totp:" + purpose + ";p:" + phoneNumber; + } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.EntityFrameworkCore/FodyWeavers.xml b/modules/identity/Sanhe.Abp.Identity.EntityFrameworkCore/FodyWeavers.xml new file mode 100644 index 0000000..1715698 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.EntityFrameworkCore/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/identity/Sanhe.Abp.Identity.EntityFrameworkCore/Sanhe.Abp.Identity.EntityFrameworkCore.csproj b/modules/identity/Sanhe.Abp.Identity.EntityFrameworkCore/Sanhe.Abp.Identity.EntityFrameworkCore.csproj new file mode 100644 index 0000000..c8acdf6 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.EntityFrameworkCore/Sanhe.Abp.Identity.EntityFrameworkCore.csproj @@ -0,0 +1,19 @@ + + + + + + + net6.0 + + + + + + + + + + + + diff --git a/modules/identity/Sanhe.Abp.Identity.EntityFrameworkCore/Sanhe/Abp/Identity/EntityFrameworkCore/AbpIdentityEntityFrameworkCoreModule.cs b/modules/identity/Sanhe.Abp.Identity.EntityFrameworkCore/Sanhe/Abp/Identity/EntityFrameworkCore/AbpIdentityEntityFrameworkCoreModule.cs new file mode 100644 index 0000000..99c759f --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.EntityFrameworkCore/Sanhe/Abp/Identity/EntityFrameworkCore/AbpIdentityEntityFrameworkCoreModule.cs @@ -0,0 +1,37 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Identity; +using Volo.Abp.Identity.EntityFrameworkCore; +using Volo.Abp.Modularity; + +namespace Sanhe.Abp.Identity.EntityFrameworkCore +{ + [DependsOn(typeof(AbpIdentityDomainModule))] + [DependsOn(typeof(Volo.Abp.Identity.EntityFrameworkCore.AbpIdentityEntityFrameworkCoreModule))] + public class AbpIdentityEntityFrameworkCoreModule : AbpModule + { + // private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner(); + + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddAbpDbContext(options => + { + options.AddRepository(); + options.AddRepository(); + }); + } + + //public override void PostConfigureServices(ServiceConfigurationContext context) + //{ + // OneTimeRunner.Run(() => + // { + // ObjectExtensionManager.Instance + // .MapEfCoreProperty( + // ExtensionIdentityUserConsts.AvatarUrlField, + // (etb, prop) => + // { + // prop.HasMaxLength(ExtensionIdentityUserConsts.MaxAvatarUrlLength); + // }); + // }); + //} + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.EntityFrameworkCore/Sanhe/Abp/Identity/EntityFrameworkCore/EfCoreIdentityRoleRepository.cs b/modules/identity/Sanhe.Abp.Identity.EntityFrameworkCore/Sanhe/Abp/Identity/EntityFrameworkCore/EfCoreIdentityRoleRepository.cs new file mode 100644 index 0000000..b245cf1 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.EntityFrameworkCore/Sanhe/Abp/Identity/EntityFrameworkCore/EfCoreIdentityRoleRepository.cs @@ -0,0 +1,97 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.Identity; +using Volo.Abp.Identity.EntityFrameworkCore; + +namespace Sanhe.Abp.Identity.EntityFrameworkCore +{ + public class EfCoreIdentityRoleRepository : Volo.Abp.Identity.EntityFrameworkCore.EfCoreIdentityRoleRepository, IIdentityRoleRepository + { + public EfCoreIdentityRoleRepository( + IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } + + public virtual async Task> GetListByIdListAsync( + List roleIds, + bool includeDetails = false, + CancellationToken cancellationToken = default + ) + { + return await (await GetDbSetAsync()).IncludeDetails(includeDetails) + .Where(role => roleIds.Contains(role.Id)) + .ToListAsync(GetCancellationToken(cancellationToken)); + } + + public virtual async Task> GetOrganizationUnitsAsync( + Guid id, + bool includeDetails = false, + CancellationToken cancellationToken = default) + { + var dbContext = await GetDbContextAsync(); + var query = from roleOU in dbContext.Set() + join ou in dbContext.OrganizationUnits.IncludeDetails(includeDetails) on roleOU.OrganizationUnitId equals ou.Id + where roleOU.RoleId == id + select ou; + + return await query.ToListAsync(GetCancellationToken(cancellationToken)); + } + + public virtual async Task> GetOrganizationUnitsAsync( + IEnumerable roleNames, + bool includeDetails = false, + CancellationToken cancellationToken = default) + { + var dbContext = await GetDbContextAsync(); + var query = from roleOU in dbContext.Set() + join role in dbContext.Roles on roleOU.RoleId equals role.Id + join ou in dbContext.OrganizationUnits.IncludeDetails(includeDetails) on roleOU.OrganizationUnitId equals ou.Id + where roleNames.Contains(role.Name) + select ou; + + return await query.ToListAsync(GetCancellationToken(cancellationToken)); + } + + public virtual async Task> GetRolesInOrganizationsListAsync( + List organizationUnitIds, + CancellationToken cancellationToken = default) + { + var query = from roleOu in (await GetDbContextAsync()).Set() + join user in await GetDbSetAsync() on roleOu.RoleId equals user.Id + where organizationUnitIds.Contains(roleOu.OrganizationUnitId) + select user; + return await query.ToListAsync(GetCancellationToken(cancellationToken)); + } + + public virtual async Task> GetRolesInOrganizationUnitAsync( + Guid organizationUnitId, + CancellationToken cancellationToken = default) + { + var query = from roleOu in (await GetDbContextAsync()).Set() + join user in await GetDbSetAsync() on roleOu.RoleId equals user.Id + where roleOu.OrganizationUnitId == organizationUnitId + select user; + return await query.ToListAsync(GetCancellationToken(cancellationToken)); + } + + public virtual async Task> GetRolesInOrganizationUnitWithChildrenAsync( + string code, + CancellationToken cancellationToken = default) + { + var dbContext = await GetDbContextAsync(); + var query = from roleOU in dbContext.Set() + join user in await GetDbSetAsync() on roleOU.RoleId equals user.Id + join ou in dbContext.Set() on roleOU.OrganizationUnitId equals ou.Id + where ou.Code.StartsWith(code) + select user; + return await query.ToListAsync(GetCancellationToken(cancellationToken)); + } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.EntityFrameworkCore/Sanhe/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs b/modules/identity/Sanhe.Abp.Identity.EntityFrameworkCore/Sanhe/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs new file mode 100644 index 0000000..3a76731 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.EntityFrameworkCore/Sanhe/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs @@ -0,0 +1,238 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.Identity; +using Volo.Abp.Identity.EntityFrameworkCore; + +namespace Sanhe.Abp.Identity.EntityFrameworkCore +{ + public class EfCoreIdentityUserRepository : Volo.Abp.Identity.EntityFrameworkCore.EfCoreIdentityUserRepository, IIdentityUserRepository + { + public EfCoreIdentityUserRepository( + IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } + + public virtual async Task IsPhoneNumberUedAsync( + string phoneNumber, + CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()).IncludeDetails(false) + .AnyAsync(user => user.PhoneNumber == phoneNumber, + GetCancellationToken(cancellationToken)); + } + + public virtual async Task IsPhoneNumberConfirmedAsync( + string phoneNumber, + CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()).IncludeDetails(false) + .AnyAsync(user => user.PhoneNumber == phoneNumber && user.PhoneNumberConfirmed, + GetCancellationToken(cancellationToken)); + } + + public virtual async Task IsNormalizedEmailConfirmedAsync( + string normalizedEmail, + CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()).IncludeDetails(false) + .AnyAsync(user => user.NormalizedEmail == normalizedEmail && user.EmailConfirmed, + GetCancellationToken(cancellationToken)); + } + + public virtual async Task FindByPhoneNumberAsync( + string phoneNumber, + bool isConfirmed = true, + bool includeDetails = false, + CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()).IncludeDetails(includeDetails) + .Where(user => user.PhoneNumber == phoneNumber && user.PhoneNumberConfirmed == isConfirmed) + .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); + } + + public virtual async Task> GetListByIdListAsync( + List userIds, + bool includeDetails = false, + CancellationToken cancellationToken = default + ) + { + return await (await GetDbSetAsync()).IncludeDetails(includeDetails) + .Where(user => userIds.Contains(user.Id)) + .ToListAsync(GetCancellationToken(cancellationToken)); + } + + public virtual async Task> GetOrganizationUnitsAsync( + Guid id, + string filter = null, + bool includeDetails = false, + int skipCount = 1, + int maxResultCount = 10, + CancellationToken cancellationToken = default + ) + { + var dbContext = await GetDbContextAsync(); + //var userUoDbSet = dbContext.Set(); + //var roleUoDbSet = dbContext.Set(); + //var userRoleDbSet = dbContext.Set(); + + //var userUo = from usrUo in userUoDbSet + // join usr in dbContext.Users on usrUo.UserId equals usr.Id + // join ou in dbContext.OrganizationUnits.IncludeDetails(includeDetails) + // on usrUo.OrganizationUnitId equals ou.Id + // where usr.Id == id + // select ou; + + //var roleUo = from urol in userRoleDbSet + // join rol in dbContext.Roles on urol.RoleId equals rol.Id + // join rolUo in roleUoDbSet on rol.Id equals rolUo.RoleId + // join ou in dbContext.OrganizationUnits.IncludeDetails(includeDetails) + // on rolUo.OrganizationUnitId equals ou.Id + // where urol.UserId == id + // select ou; + + var query = from userOU in dbContext.Set() + join ro in dbContext.Set() on userOU.UserId equals ro.UserId + join ou in dbContext.OrganizationUnits.IncludeDetails(includeDetails) + on userOU.OrganizationUnitId equals ou.Id + where userOU.UserId == id + select ou; + + return await query + .WhereIf(!filter.IsNullOrWhiteSpace(), ou => ou.Code.Contains(filter) || ou.DisplayName.Contains(filter)) + .PageBy(skipCount, maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)); + } + + public virtual async Task GetUsersInOrganizationUnitCountAsync( + Guid organizationUnitId, + string filter = null, + CancellationToken cancellationToken = default + ) + { + var dbContext = await GetDbContextAsync(); + var query = from userOu in dbContext.Set() + join user in await GetDbSetAsync() on userOu.UserId equals user.Id + where userOu.OrganizationUnitId == organizationUnitId + select user; + return await query + .WhereIf(!filter.IsNullOrWhiteSpace(), + user => user.Name.Contains(filter) || user.UserName.Contains(filter) || + user.Surname.Contains(filter) || user.Email.Contains(filter) || + user.PhoneNumber.Contains(filter)) + .LongCountAsync(GetCancellationToken(cancellationToken)); + } + + public virtual async Task> GetUsersInOrganizationUnitAsync( + Guid organizationUnitId, + string filter = null, + int skipCount = 1, + int maxResultCount = 10, + CancellationToken cancellationToken = default + ) + { + var dbContext = await GetDbContextAsync(); + var query = from userOu in dbContext.Set() + join user in await GetDbSetAsync() on userOu.UserId equals user.Id + where userOu.OrganizationUnitId == organizationUnitId + select user; + return await query + .WhereIf(!filter.IsNullOrWhiteSpace(), + user => user.Name.Contains(filter) || user.UserName.Contains(filter) || + user.Surname.Contains(filter) || user.Email.Contains(filter) || + user.PhoneNumber.Contains(filter)) + .PageBy(skipCount, maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)); + } + + public virtual async Task GetUsersInOrganizationsListCountAsync( + List organizationUnitIds, + string filter = null, + CancellationToken cancellationToken = default + ) + { + var dbContext = await GetDbContextAsync(); + var query = from userOu in dbContext.Set() + join user in await GetDbSetAsync() on userOu.UserId equals user.Id + where organizationUnitIds.Contains(userOu.OrganizationUnitId) + select user; + return await query + .WhereIf(!filter.IsNullOrWhiteSpace(), + user => user.Name.Contains(filter) || user.UserName.Contains(filter) || + user.Surname.Contains(filter) || user.Email.Contains(filter) || + user.PhoneNumber.Contains(filter)) + .LongCountAsync(GetCancellationToken(cancellationToken)); + } + + public virtual async Task> GetUsersInOrganizationsListAsync( + List organizationUnitIds, + string filter = null, + int skipCount = 1, + int maxResultCount = 10, + CancellationToken cancellationToken = default + ) + { + var dbContext = await GetDbContextAsync(); + var query = from userOu in dbContext.Set() + join user in await GetDbSetAsync() on userOu.UserId equals user.Id + where organizationUnitIds.Contains(userOu.OrganizationUnitId) + select user; + return await query + .WhereIf(!filter.IsNullOrWhiteSpace(), + user => user.Name.Contains(filter) || user.UserName.Contains(filter) || + user.Surname.Contains(filter) || user.Email.Contains(filter) || + user.PhoneNumber.Contains(filter)) + .PageBy(skipCount, maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)); + } + + public virtual async Task GetUsersInOrganizationUnitWithChildrenCountAsync( + string code, + string filter = null, + CancellationToken cancellationToken = default + ) + { + var dbContext = await GetDbContextAsync(); + var query = from userOu in dbContext.Set() + join user in await GetDbSetAsync() on userOu.UserId equals user.Id + join ou in dbContext.Set() on userOu.OrganizationUnitId equals ou.Id + where ou.Code.StartsWith(code) + select user; + return await query + .WhereIf(!filter.IsNullOrWhiteSpace(), + user => user.Name.Contains(filter) || user.UserName.Contains(filter) || + user.Surname.Contains(filter) || user.Email.Contains(filter) || + user.PhoneNumber.Contains(filter)) + .LongCountAsync(GetCancellationToken(cancellationToken)); + } + + public virtual async Task> GetUsersInOrganizationUnitWithChildrenAsync( + string code, + string filter = null, + int skipCount = 1, + int maxResultCount = 10, + CancellationToken cancellationToken = default + ) + { + var dbContext = await GetDbContextAsync(); + var query = from userOu in dbContext.Set() + join user in await GetDbSetAsync() on userOu.UserId equals user.Id + join ou in dbContext.Set() on userOu.OrganizationUnitId equals ou.Id + where ou.Code.StartsWith(code) + select user; + return await query + .WhereIf(!filter.IsNullOrWhiteSpace(), + user => user.Name.Contains(filter) || user.UserName.Contains(filter) || + user.Surname.Contains(filter) || user.Email.Contains(filter) || + user.PhoneNumber.Contains(filter)) + .PageBy(skipCount, maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)); + } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.HttpApi.Client/FodyWeavers.xml b/modules/identity/Sanhe.Abp.Identity.HttpApi.Client/FodyWeavers.xml new file mode 100644 index 0000000..1715698 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.HttpApi.Client/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/identity/Sanhe.Abp.Identity.HttpApi.Client/Sanhe.Abp.Identity.HttpApi.Client.csproj b/modules/identity/Sanhe.Abp.Identity.HttpApi.Client/Sanhe.Abp.Identity.HttpApi.Client.csproj new file mode 100644 index 0000000..e71bfce --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.HttpApi.Client/Sanhe.Abp.Identity.HttpApi.Client.csproj @@ -0,0 +1,19 @@ + + + + + + + netstandard2.0 + + + + + + + + + + + + diff --git a/modules/identity/Sanhe.Abp.Identity.HttpApi.Client/Sanhe/Abp/Identity/AbpIdentityHttpApiClientModule.cs b/modules/identity/Sanhe.Abp.Identity.HttpApi.Client/Sanhe/Abp/Identity/AbpIdentityHttpApiClientModule.cs new file mode 100644 index 0000000..a7b895d --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.HttpApi.Client/Sanhe/Abp/Identity/AbpIdentityHttpApiClientModule.cs @@ -0,0 +1,20 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Identity; +using Volo.Abp.Modularity; + +namespace Sanhe.Abp.Identity +{ + [DependsOn( + typeof(Volo.Abp.Identity.AbpIdentityHttpApiClientModule), + typeof(AbpIdentityApplicationContractsModule))] + public class AbpIdentityHttpApiClientModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddHttpClientProxies( + typeof(AbpIdentityApplicationContractsModule).Assembly, + IdentityRemoteServiceConsts.RemoteServiceName + ); + } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.HttpApi/FodyWeavers.xml b/modules/identity/Sanhe.Abp.Identity.HttpApi/FodyWeavers.xml new file mode 100644 index 0000000..1715698 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.HttpApi/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/identity/Sanhe.Abp.Identity.HttpApi/Sanhe.Abp.Identity.HttpApi.csproj b/modules/identity/Sanhe.Abp.Identity.HttpApi/Sanhe.Abp.Identity.HttpApi.csproj new file mode 100644 index 0000000..c305a65 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.HttpApi/Sanhe.Abp.Identity.HttpApi.csproj @@ -0,0 +1,19 @@ + + + + + + + net6.0 + + True + + + + + + + + + + diff --git a/modules/identity/Sanhe.Abp.Identity.HttpApi/Sanhe/Abp/Identity/AbpIdentityHttpApiModule.cs b/modules/identity/Sanhe.Abp.Identity.HttpApi/Sanhe/Abp/Identity/AbpIdentityHttpApiModule.cs new file mode 100644 index 0000000..fa4fb80 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.HttpApi/Sanhe/Abp/Identity/AbpIdentityHttpApiModule.cs @@ -0,0 +1,27 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.AspNetCore.Mvc.Localization; +using Volo.Abp.Identity.Localization; +using Volo.Abp.Modularity; + +namespace Sanhe.Abp.Identity +{ + [DependsOn( + typeof(Volo.Abp.Identity.AbpIdentityHttpApiModule), + typeof(AbpIdentityApplicationContractsModule))] + public class AbpIdentityHttpApiModule : AbpModule + { + public override void PreConfigureServices(ServiceConfigurationContext context) + { + PreConfigure(options => + { + options.AddAssemblyResource(typeof(IdentityResource), typeof(AbpIdentityApplicationContractsModule).Assembly); + options.AddAssemblyResource(typeof(IdentityResource), typeof(Volo.Abp.Identity.AbpIdentityApplicationContractsModule).Assembly); + }); + + PreConfigure(mvcBuilder => + { + mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpIdentityHttpApiModule).Assembly); + }); + } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.HttpApi/Sanhe/Abp/Identity/IdentityClaimTypeController.cs b/modules/identity/Sanhe.Abp.Identity.HttpApi/Sanhe/Abp/Identity/IdentityClaimTypeController.cs new file mode 100644 index 0000000..fd86f26 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.HttpApi/Sanhe/Abp/Identity/IdentityClaimTypeController.cs @@ -0,0 +1,64 @@ +using Microsoft.AspNetCore.Mvc; +using Sanhe.Abp.Identity.Dto; +using System; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.Identity; + +namespace Sanhe.Abp.Identity +{ + [RemoteService(true, Name = IdentityRemoteServiceConsts.RemoteServiceName)] + [Area("identity")] + [ControllerName("ClaimType")] + [Route("api/identity/claim-types")] + public class IdentityClaimTypeController : AbpController, IIdentityClaimTypeAppService + { + protected IIdentityClaimTypeAppService IdentityClaimTypeAppService { get; } + public IdentityClaimTypeController(IIdentityClaimTypeAppService identityClaimTypeAppService) + { + IdentityClaimTypeAppService = identityClaimTypeAppService; + } + + [HttpPost] + public virtual async Task CreateAsync(IdentityClaimTypeCreateDto input) + { + return await IdentityClaimTypeAppService.CreateAsync(input); + } + + [HttpDelete] + [Route("{id}")] + public virtual async Task DeleteAsync(Guid id) + { + await IdentityClaimTypeAppService.DeleteAsync(id); + } + + [HttpGet] + [Route("actived-list")] + public virtual async Task> GetAllListAsync() + { + return await IdentityClaimTypeAppService.GetAllListAsync(); + } + + [HttpGet] + [Route("{id}")] + public virtual async Task GetAsync(Guid id) + { + return await IdentityClaimTypeAppService.GetAsync(id); + } + + [HttpGet] + public virtual async Task> GetListAsync(IdentityClaimTypeGetByPagedDto input) + { + return await IdentityClaimTypeAppService.GetListAsync(input); + } + + [HttpPut] + [Route("{id}")] + public virtual async Task UpdateAsync(Guid id, IdentityClaimTypeUpdateDto input) + { + return await IdentityClaimTypeAppService.UpdateAsync(id, input); + } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.HttpApi/Sanhe/Abp/Identity/IdentityRoleController.cs b/modules/identity/Sanhe.Abp.Identity.HttpApi/Sanhe/Abp/Identity/IdentityRoleController.cs new file mode 100644 index 0000000..dc03589 --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.HttpApi/Sanhe/Abp/Identity/IdentityRoleController.cs @@ -0,0 +1,82 @@ +using Microsoft.AspNetCore.Mvc; +using Sanhe.Abp.Identity.Dto; +using System; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.Identity; + +namespace Sanhe.Abp.Identity +{ + [RemoteService(true, Name = IdentityRemoteServiceConsts.RemoteServiceName)] + [Area("identity")] + [ControllerName("Role")] + [Route("api/identity/roles")] + public class IdentityRoleController : AbpController, IIdentityRoleAppService + { + protected IIdentityRoleAppService RoleAppService { get; } + public IdentityRoleController( + IIdentityRoleAppService roleAppService) + { + RoleAppService = roleAppService; + } + + #region OrganizationUnit + + [HttpGet] + [Route("{id}/organization-units")] + public virtual async Task> GetOrganizationUnitsAsync(Guid id) + { + return await RoleAppService.GetOrganizationUnitsAsync(id); + } + + [HttpPut] + [Route("{id}/organization-units")] + public virtual async Task SetOrganizationUnitsAsync(Guid id, IdentityRoleAddOrRemoveOrganizationUnitDto input) + { + await RoleAppService.SetOrganizationUnitsAsync(id, input); + } + + [HttpDelete] + [Route("{id}/organization-units/{ouId}")] + public virtual async Task RemoveOrganizationUnitsAsync(Guid id, Guid ouId) + { + await RoleAppService.RemoveOrganizationUnitsAsync(id, ouId); + } + + #endregion + + #region Claim + + [HttpGet] + [Route("{id}/claims")] + public virtual async Task> GetClaimsAsync(Guid id) + { + return await RoleAppService.GetClaimsAsync(id); + } + + [HttpPost] + [Route("{id}/claims")] + public virtual async Task AddClaimAsync(Guid id, IdentityRoleClaimCreateDto input) + { + await RoleAppService.AddClaimAsync(id, input); + } + + [HttpPut] + [Route("{id}/claims")] + public virtual async Task UpdateClaimAsync(Guid id, IdentityRoleClaimUpdateDto input) + { + await RoleAppService.UpdateClaimAsync(id, input); + } + + [HttpDelete] + [Route("{id}/claims")] + public virtual async Task DeleteClaimAsync(Guid id, IdentityRoleClaimDeleteDto input) + { + await RoleAppService.DeleteClaimAsync(id, input); + } + + #endregion + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.HttpApi/Sanhe/Abp/Identity/IdentityUserController.cs b/modules/identity/Sanhe.Abp.Identity.HttpApi/Sanhe/Abp/Identity/IdentityUserController.cs new file mode 100644 index 0000000..36d732c --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.HttpApi/Sanhe/Abp/Identity/IdentityUserController.cs @@ -0,0 +1,104 @@ +using Microsoft.AspNetCore.Mvc; +using Sanhe.Abp.Identity.Dto; +using System; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.Identity; + +namespace Sanhe.Abp.Identity +{ + [RemoteService(true, Name = IdentityRemoteServiceConsts.RemoteServiceName)] + [Area("identity")] + [ControllerName("User")] + [Route("api/identity/users")] + public class IdentityUserController : AbpController, IIdentityUserAppService + { + protected IIdentityUserAppService UserAppService { get; } + public IdentityUserController( + IIdentityUserAppService userAppService) + { + UserAppService = userAppService; + } + + #region OrganizationUnit + + [HttpGet] + [Route("{id}/organization-units")] + public virtual async Task> GetOrganizationUnitsAsync(Guid id) + { + return await UserAppService.GetOrganizationUnitsAsync(id); + } + + [HttpPut] + [Route("{id}/organization-units")] + public virtual async Task SetOrganizationUnitsAsync(Guid id, IdentityUserOrganizationUnitUpdateDto input) + { + await UserAppService.SetOrganizationUnitsAsync(id, input); + } + + [HttpDelete] + [Route("{id}/organization-units/{ouId}")] + public virtual async Task RemoveOrganizationUnitsAsync(Guid id, Guid ouId) + { + await UserAppService.RemoveOrganizationUnitsAsync(id, ouId); + } + + #endregion + + #region Claim + + [HttpGet] + [Route("{id}/claims")] + public virtual async Task> GetClaimsAsync(Guid id) + { + return await UserAppService.GetClaimsAsync(id); + } + + [HttpPost] + [Route("{id}/claims")] + public virtual async Task AddClaimAsync(Guid id, IdentityUserClaimCreateDto input) + { + await UserAppService.AddClaimAsync(id, input); + } + + [HttpPut] + [Route("{id}/claims")] + public virtual async Task UpdateClaimAsync(Guid id, IdentityUserClaimUpdateDto input) + { + await UserAppService.UpdateClaimAsync(id, input); + } + + [HttpDelete] + [Route("{id}/claims")] + public virtual async Task DeleteClaimAsync(Guid id, IdentityUserClaimDeleteDto input) + { + await UserAppService.DeleteClaimAsync(id, input); + } + + #endregion + + + [HttpPut] + [Route("change-two-factor")] + public virtual async Task ChangeTwoFactorEnabledAsync(Guid id, TwoFactorEnabledDto input) + { + await UserAppService.ChangeTwoFactorEnabledAsync(id, input); + } + + [HttpPut] + [Route("{id}/lock/{seconds}")] + public virtual async Task LockAsync(Guid id, int seconds) + { + await UserAppService.LockAsync(id, seconds); + } + + [HttpPut] + [Route("{id}/unlock")] + public virtual async Task UnLockAsync(Guid id) + { + await UserAppService.UnLockAsync(id); + } + } +} diff --git a/modules/identity/Sanhe.Abp.Identity.HttpApi/Sanhe/Abp/Identity/OrganizationUnitController.cs b/modules/identity/Sanhe.Abp.Identity.HttpApi/Sanhe/Abp/Identity/OrganizationUnitController.cs new file mode 100644 index 0000000..8686cfe --- /dev/null +++ b/modules/identity/Sanhe.Abp.Identity.HttpApi/Sanhe/Abp/Identity/OrganizationUnitController.cs @@ -0,0 +1,143 @@ +using Microsoft.AspNetCore.Mvc; +using Sanhe.Abp.Identity.Dto; +using System; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.Identity; + +namespace Sanhe.Abp.Identity +{ + [RemoteService(Name = IdentityRemoteServiceConsts.RemoteServiceName)] + [Area("identity")] + [ControllerName("organization-units")] + [Route("api/identity/organization-units")] + public class OrganizationUnitController : AbpController, IOrganizationUnitAppService + { + protected IOrganizationUnitAppService OrganizationUnitAppService { get; } + + public OrganizationUnitController( + IOrganizationUnitAppService organizationUnitAppService) + { + OrganizationUnitAppService = organizationUnitAppService; + } + + [HttpPost] + public virtual async Task CreateAsync(OrganizationUnitCreateDto input) + { + return await OrganizationUnitAppService.CreateAsync(input); + } + + [HttpDelete] + [Route("{id}")] + public virtual async Task DeleteAsync(Guid id) + { + await OrganizationUnitAppService.DeleteAsync(id); + } + + [HttpGet] + [Route("find-children")] + public virtual async Task> FindChildrenAsync(OrganizationUnitGetChildrenDto input) + { + return await OrganizationUnitAppService.FindChildrenAsync(input); + } + + [HttpGet] + [Route("{id}")] + public virtual async Task GetAsync(Guid id) + { + return await OrganizationUnitAppService.GetAsync(id); + } + + [HttpGet] + [Route("root-node")] + public virtual async Task> GetRootAsync() + { + return await OrganizationUnitAppService.GetRootAsync(); + } + + [HttpGet] + [Route("last-children")] + public virtual async Task GetLastChildOrNullAsync(Guid? parentId) + { + return await OrganizationUnitAppService.GetLastChildOrNullAsync(parentId); + } + + [HttpGet] + [Route("all")] + public virtual async Task> GetAllListAsync() + { + return await OrganizationUnitAppService.GetAllListAsync(); + } + + [HttpGet] + public virtual async Task> GetListAsync(OrganizationUnitGetByPagedDto input) + { + return await OrganizationUnitAppService.GetListAsync(input); + } + + [HttpGet] + [Route("{id}/role-names")] + public virtual async Task> GetRoleNamesAsync(Guid id) + { + return await OrganizationUnitAppService.GetRoleNamesAsync(id); + } + + [HttpGet] + [Route("{id}/unadded-roles")] + public virtual async Task> GetUnaddedRolesAsync(Guid id, OrganizationUnitGetUnaddedRoleByPagedDto input) + { + return await OrganizationUnitAppService.GetUnaddedRolesAsync(id, input); + } + + [HttpGet] + [Route("{id}/roles")] + public virtual async Task> GetRolesAsync(Guid id, PagedAndSortedResultRequestDto input) + { + return await OrganizationUnitAppService.GetRolesAsync(id, input); + } + + [HttpGet] + [Route("{id}/unadded-users")] + public virtual async Task> GetUnaddedUsersAsync(Guid id, OrganizationUnitGetUnaddedUserByPagedDto input) + { + return await OrganizationUnitAppService.GetUnaddedUsersAsync(id, input); + } + + [HttpGet] + [Route("{id}/users")] + public virtual async Task> GetUsersAsync(Guid id, GetIdentityUsersInput input) + { + return await OrganizationUnitAppService.GetUsersAsync(id, input); + } + + [HttpPost] + [Route("{id}/users")] + public virtual async Task AddUsersAsync(Guid id, OrganizationUnitAddUserDto input) + { + await OrganizationUnitAppService.AddUsersAsync(id, input); + } + + [HttpPost] + [Route("{id}/roles")] + public virtual async Task AddRolesAsync(Guid id, OrganizationUnitAddRoleDto input) + { + await OrganizationUnitAppService.AddRolesAsync(id, input); + } + + [HttpPut] + [Route("{id}/move")] + public virtual async Task MoveAsync(Guid id, OrganizationUnitMoveDto input) + { + await OrganizationUnitAppService.MoveAsync(id, input); + } + + [HttpPut] + [Route("{id}")] + public virtual async Task UpdateAsync(Guid id, OrganizationUnitUpdateDto input) + { + return await OrganizationUnitAppService.UpdateAsync(id, input); + } + } +} diff --git a/services/book-store/BookStore.csproj b/services/book-store/BookStore.csproj index d369894..fc2394d 100644 --- a/services/book-store/BookStore.csproj +++ b/services/book-store/BookStore.csproj @@ -28,9 +28,6 @@ - - - @@ -486,6 +483,9 @@ + + + diff --git a/services/book-store/BookStoreModule.cs b/services/book-store/BookStoreModule.cs index da7a570..6a05fd8 100644 --- a/services/book-store/BookStoreModule.cs +++ b/services/book-store/BookStoreModule.cs @@ -44,8 +44,8 @@ using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore.PostgreSql; using Volo.Abp.FeatureManagement; using Volo.Abp.FeatureManagement.EntityFrameworkCore; -using Volo.Abp.Identity; -using Volo.Abp.Identity.EntityFrameworkCore; +using Sanhe.Abp.Identity; +using Sanhe.Abp.Identity.EntityFrameworkCore; using Volo.Abp.IdentityServer.EntityFrameworkCore; using Volo.Abp.Localization; using Volo.Abp.Localization.ExceptionHandling;