From e20bc7ddddf19485c69a1b08d52810f1d4ed33ce Mon Sep 17 00:00:00 2001 From: wuweilai <30889371+15168440402@users.noreply.github.com> Date: Tue, 21 Jun 2022 13:34:58 +0800 Subject: [PATCH] =?UTF-8?q?feature(oidc):add=20Oidc.EntityFramework?= =?UTF-8?q?=E3=80=81Oidc.Cache.Storage=20(#78)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add oidc project * feat(oidc):oidc * feat(oidc):oidc * feat(oidc):oidc * feat(oidc):oidc * feat(oidc):oidc * feat(oidc):oidc * feat(oidc):oidc * feat(oidc):oidc * feat:add redis cache options * feat(oidc):oidc * feat(oidc):oidc * feat(oidc):oidc * feat:update cache * feat(oidc):oidc * feat(oidc)Loidc * feat(oidc):oidc * feat(oidc):oidc * refactor:formatting code * feat(oidc):remove AddAllAsync,add ResetAsync * refactor(code):refactor code * refactor:refactor code * refactor:refactor code * refactor:refactor code * refactor(code):refactor code * merge:merges the latest code in the main branch Co-authored-by: Mayue --- Masa.Contrib.sln | 167 +++++++++++++----- ...b.Authentication.Oidc.Cache.Storage.csproj | 22 +++ .../ServiceCollectionExtensions.cs | 18 ++ .../Stores/ClientStore.cs | 22 +++ .../Stores/DeviceFlowStore.cs | 32 ++++ .../Stores/PersistedGrantStore.cs | 32 ++++ .../Stores/ResourceStore.cs | 58 ++++++ .../_Imports.cs | 9 + .../Caches/ApiResourceCache.cs | 72 ++++++++ .../Caches/ApiScopeCache.cs | 72 ++++++++ .../Caches/ClientCache.cs | 38 ++++ .../Caches/IdentityResourceCache.cs | 72 ++++++++ ...a.Contrib.Authentication.Oidc.Cache.csproj | 18 ++ .../Models/CacheKeyConstants.cs | 12 ++ .../Models/Mapper.cs | 105 +++++++++++ .../ServiceCollectionExtensions.cs | 18 ++ .../Utils/CollectionExtensions.cs | 52 ++++++ .../_Imports.cs | 15 ++ .../Caches/SyncCache.cs | 98 ++++++++++ .../DbContexts/OidcDbContext.cs | 17 ++ ...ApiResourceClaimEntityTypeConfiguration.cs | 12 ++ .../ApiResourceEntityTypeConfiguration.cs | 20 +++ ...ResourcePropertyEntityTypeConfiguration.cs | 13 ++ ...ApiResourceScopeEntityTypeConfiguration.cs | 12 ++ ...piResourceSecretEntityTypeConfiguration.cs | 14 ++ .../ApiScopeClaimEntityTypeConfiguration.cs | 12 ++ .../ApiScopeEntityTypeConfiguration.cs | 18 ++ ...ApiScopePropertyEntityTypeConfiguration.cs | 13 ++ .../ClientClaimEntityTypeConfiguration.cs | 13 ++ ...ClientCorsOriginEntityTypeConfiguration.cs | 12 ++ .../ClientEntityTypeConfiguration.cs | 35 ++++ .../ClientGrantTypeEntityTypeConfiguration.cs | 12 ++ ...ntIdPRestrictionEntityTypeConfiguration.cs | 12 ++ ...ogoutRedirectUriEntityTypeConfiguration.cs | 12 ++ .../ClientPropertyEntityTypeConfiguration.cs | 13 ++ ...lientRedirectUriEntityTypeConfiguration.cs | 12 ++ .../ClientScopeEntityTypeConfiguration.cs | 12 ++ .../ClientSecretEntityTypeConfiguration.cs | 14 ++ .../DeviceFlowCodesEntityTypeConfiguration.cs | 27 +++ ...ityResourceClaimEntityTypeConfiguration.cs | 12 ++ ...IdentityResourceEntityTypeConfiguration.cs | 18 ++ ...ResourcePropertyEntityTypeConfiguration.cs | 13 ++ .../PersistedGrantEntityTypeConfiguration.cs | 27 +++ .../UserClaimEntityTypeConfiguration.cs | 14 ++ ...entication.Oidc.EntityFrameworkCore.csproj | 19 ++ .../Repositories/ApiResourceRepository.cs | 89 ++++++++++ .../Repositories/ApiScopeRepository.cs | 87 +++++++++ .../Repositories/ClientRepository.cs | 90 ++++++++++ .../IdentityResourceRepository.cs | 112 ++++++++++++ .../Repositories/UserClaimRepository.cs | 92 ++++++++++ .../ServiceCollectionExtensions.cs | 43 +++++ .../_Imports.cs | 15 ++ src/BuildingBlocks/MASA.BuildingBlocks | 2 +- 53 files changed, 1822 insertions(+), 48 deletions(-) create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/Masa.Contrib.Authentication.Oidc.Cache.Storage.csproj create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/ServiceCollectionExtensions.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/Stores/ClientStore.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/Stores/DeviceFlowStore.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/Stores/PersistedGrantStore.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/Stores/ResourceStore.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/_Imports.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Caches/ApiResourceCache.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Caches/ApiScopeCache.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Caches/ClientCache.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Caches/IdentityResourceCache.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Masa.Contrib.Authentication.Oidc.Cache.csproj create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Models/CacheKeyConstants.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Models/Mapper.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/ServiceCollectionExtensions.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Utils/CollectionExtensions.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/_Imports.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Caches/SyncCache.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/DbContexts/OidcDbContext.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiResourceClaimEntityTypeConfiguration.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiResourceEntityTypeConfiguration.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiResourcePropertyEntityTypeConfiguration.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiResourceScopeEntityTypeConfiguration.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiResourceSecretEntityTypeConfiguration.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiScopeClaimEntityTypeConfiguration.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiScopeEntityTypeConfiguration.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiScopePropertyEntityTypeConfiguration.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientClaimEntityTypeConfiguration.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientCorsOriginEntityTypeConfiguration.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientEntityTypeConfiguration.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientGrantTypeEntityTypeConfiguration.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientIdPRestrictionEntityTypeConfiguration.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientPostLogoutRedirectUriEntityTypeConfiguration.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientPropertyEntityTypeConfiguration.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientRedirectUriEntityTypeConfiguration.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientScopeEntityTypeConfiguration.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientSecretEntityTypeConfiguration.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/DeviceFlowCodesEntityTypeConfiguration.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/IdentityResourceClaimEntityTypeConfiguration.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/IdentityResourceEntityTypeConfiguration.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/IdentityResourcePropertyEntityTypeConfiguration.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/PersistedGrantEntityTypeConfiguration.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/UserClaimEntityTypeConfiguration.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.csproj create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Repositories/ApiResourceRepository.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Repositories/ApiScopeRepository.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Repositories/ClientRepository.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Repositories/IdentityResourceRepository.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Repositories/UserClaimRepository.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/ServiceCollectionExtensions.cs create mode 100644 src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/_Imports.cs diff --git a/Masa.Contrib.sln b/Masa.Contrib.sln index 837b10d35..3c90068e4 100644 --- a/Masa.Contrib.sln +++ b/Masa.Contrib.sln @@ -28,6 +28,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "solution items", "solution items", "{9F6F9899-D5F1-444A-BE56-64F949550D22}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig + Directory.Build.props = Directory.Build.props nuget.config = nuget.config EndProjectSection EndProject @@ -221,51 +222,67 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Data.IdGenerat EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.BasicAbility.Auth.Tests", "test\Masa.Contrib.BasicAbility.Auth.Tests\Masa.Contrib.BasicAbility.Auth.Tests.csproj", "{2B644A8C-F0EE-4566-AB78-9E1C6D4185A3}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Data.IdGenerator.Snowflake.Distributed.Redis", "src\Data\IdGenerator\Masa.Contrib.Data.IdGenerator.Snowflake.Distributed.Redis\Masa.Contrib.Data.IdGenerator.Snowflake.Distributed.Redis.csproj", "{DC50078D-D706-4CB9-A301-F47CB3F46007}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Authentication", "Authentication", "{4995742C-033A-4147-89E7-7FFE7681C971}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.BuildingBlocks.Identity.IdentityModel", "src\BuildingBlocks\MASA.BuildingBlocks\src\Identity\Masa.BuildingBlocks.Identity.IdentityModel\Masa.BuildingBlocks.Identity.IdentityModel.csproj", "{2FD02408-DF1D-48E0-94F2-9910E76D8B6E}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Authentication", "Authentication", "{B7F5651E-C4CB-413E-AF6E-420D1AFB7EA6}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "IdGenerator", "IdGenerator", "{E6363F59-2BA4-4AA7-8578-C433A2C2567F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Data.IdGenerator.Snowflake.Distributed.Redis", "src\Data\IdGenerator\Masa.Contrib.Data.IdGenerator.Snowflake.Distributed.Redis\Masa.Contrib.Data.IdGenerator.Snowflake.Distributed.Redis.csproj", "{DC50078D-D706-4CB9-A301-F47CB3F46007}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Identity", "Identity", "{8E9691A2-BBCA-4A0F-906D-61D159F78B3B}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "IdGenerator", "IdGenerator", "{E6363F59-2BA4-4AA7-8578-C433A2C2567F}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Data.IdGenerator.Snowflake.BenchmarkDotnet.Tests", "test\Masa.Contrib.Data.IdGenerator.Snowflake.BenchmarkDotnet.Tests\Masa.Contrib.Data.IdGenerator.Snowflake.BenchmarkDotnet.Tests.csproj", "{D8E85337-A779-48FC-B822-CE8A850661DC}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.Contrib.Identity.IdentityModel", "src\Identity\Masa.Contrib.Identity.IdentityModel\Masa.Contrib.Identity.IdentityModel.csproj", "{A0185D9A-69AB-4668-97F6-132C7D0947AA}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.BuildingBlocks.Data.MappingExtensions", "src\BuildingBlocks\MASA.BuildingBlocks\src\Data\Masa.BuildingBlocks.Data.MappingExtensions\Masa.BuildingBlocks.Data.MappingExtensions.csproj", "{30DC35DF-9D86-443C-B26C-9053E6FCA434}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Data.IdGenerator.NormalGuid", "src\Data\IdGenerator\Masa.Contrib.Data.IdGenerator.NormalGuid\Masa.Contrib.Data.IdGenerator.NormalGuid.csproj", "{24E5BF57-33B6-4D5B-A32F-2F64D1A5954F}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Data.IdGenerator.SequentialGuid", "src\Data\IdGenerator\Masa.Contrib.Data.IdGenerator.SequentialGuid\Masa.Contrib.Data.IdGenerator.SequentialGuid.csproj", "{B15F4561-E511-42EA-A02E-F772BAF41E20}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.Contrib.Data.IdGenerator.SequentialGuid.Tests", "test\Masa.Contrib.Data.IdGenerator.SequentialGuid.Tests\Masa.Contrib.Data.IdGenerator.SequentialGuid.Tests.csproj", "{32488758-25C9-4257-9B98-DAA034C19909}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Data.IdGenerator.SequentialGuid.Tests", "test\Masa.Contrib.Data.IdGenerator.SequentialGuid.Tests\Masa.Contrib.Data.IdGenerator.SequentialGuid.Tests.csproj", "{32488758-25C9-4257-9B98-DAA034C19909}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.BuildingBlocks.Authentication.Oidc.Cache", "src\BuildingBlocks\MASA.BuildingBlocks\src\Authentication\Masa.BuildingBlocks.Authentication.Oidc.Cache\Masa.BuildingBlocks.Authentication.Oidc.Cache.csproj", "{4B94CAF6-134D-4F89-8F2D-72A4FB363B59}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.BuildingBlocks.Authentication.Oidc.Domain", "src\BuildingBlocks\MASA.BuildingBlocks\src\Authentication\Masa.BuildingBlocks.Authentication.Oidc.Domain\Masa.BuildingBlocks.Authentication.Oidc.Domain.csproj", "{54936F20-EEFC-405B-8646-76F200A5C8F7}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.Contrib.Identity.IdentityModel.Tests", "test\Masa.Contrib.Identity.IdentityModel.Tests\Masa.Contrib.Identity.IdentityModel.Tests.csproj", "{E08AF686-91D4-48B4-B5DF-90474D18E984}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.BuildingBlocks.Authentication.Oidc.Models", "src\BuildingBlocks\MASA.BuildingBlocks\src\Authentication\Masa.BuildingBlocks.Authentication.Oidc.Models\Masa.BuildingBlocks.Authentication.Oidc.Models.csproj", "{546EE1A2-DB6B-49D3-8919-33624FEF2498}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.BuildingBlocks.Authentication.Oidc.Storage", "src\BuildingBlocks\MASA.BuildingBlocks\src\Authentication\Masa.BuildingBlocks.Authentication.Oidc.Storage\Masa.BuildingBlocks.Authentication.Oidc.Storage.csproj", "{B603B92A-1203-4E28-9D15-2AF1CE4E9510}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Authentication.Oidc.Cache", "src\Authentication\Masa.Contrib.Authentication.Oidc.Cache\Masa.Contrib.Authentication.Oidc.Cache.csproj", "{FBF18906-7113-4036-BAEB-56E925F7D301}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Authentication.Oidc.Cache.Storage", "src\Authentication\Masa.Contrib.Authentication.Oidc.Cache.Storage\Masa.Contrib.Authentication.Oidc.Cache.Storage.csproj", "{661A5C41-A5DE-45C9-A7CF-B59C2B9B23E0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Authentication.Oidc.EntityFrameworkCore", "src\Authentication\Masa.Contrib.Authentication.Oidc.EntityFrameworkCore\Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.csproj", "{F2E1018A-F423-4782-BE9D-6169C669AD43}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.BuildingBlocks.Identity.IdentityModel", "src\BuildingBlocks\MASA.BuildingBlocks\src\Identity\Masa.BuildingBlocks.Identity.IdentityModel\Masa.BuildingBlocks.Identity.IdentityModel.csproj", "{18634B69-0ED1-4C64-9735-4DFD2B2B0E9B}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DistributedLocking", "DistributedLocking", "{07BD7788-9DC0-4BD0-9861-0C9AC13B4EB8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.Contrib.Data.DistributedLocking.Local", "src\Data\DistributedLocking\Masa.Contrib.Data.DistributedLocking.Local\Masa.Contrib.Data.DistributedLocking.Local.csproj", "{338EA0ED-B7B2-44D8-9F34-235C484E3497}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Data.DistributedLocking.Local", "src\Data\DistributedLocking\Masa.Contrib.Data.DistributedLocking.Local\Masa.Contrib.Data.DistributedLocking.Local.csproj", "{338EA0ED-B7B2-44D8-9F34-235C484E3497}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Data.DistributedLocking.Medallion", "src\Data\DistributedLocking\Masa.Contrib.Data.DistributedLocking.Medallion\Masa.Contrib.Data.DistributedLocking.Medallion.csproj", "{C74B04E6-6C6E-4DE0-BAF3-94224F422D60}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Data.DistributedLocking.Medallion.SqlServer", "src\Data\DistributedLocking\Masa.Contrib.Data.DistributedLocking.Medallion.SqlServer\Masa.Contrib.Data.DistributedLocking.Medallion.SqlServer.csproj", "{933050A7-AB8A-4653-AB90-A7D5FBF38C7A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.Contrib.Data.DistributedLocking.Medallion", "src\Data\DistributedLocking\Masa.Contrib.Data.DistributedLocking.Medallion\Masa.Contrib.Data.DistributedLocking.Medallion.csproj", "{C74B04E6-6C6E-4DE0-BAF3-94224F422D60}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Data.DistributedLocking.Medallion.Redis", "src\Data\DistributedLocking\Masa.Contrib.Data.DistributedLocking.Medallion.Redis\Masa.Contrib.Data.DistributedLocking.Medallion.Redis.csproj", "{2D849FCE-7EF7-4932-8022-422F5B0F1AC8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.Contrib.Data.DistributedLocking.Medallion.SqlServer", "src\Data\DistributedLocking\Masa.Contrib.Data.DistributedLocking.Medallion.SqlServer\Masa.Contrib.Data.DistributedLocking.Medallion.SqlServer.csproj", "{933050A7-AB8A-4653-AB90-A7D5FBF38C7A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Data.DistributedLocking.Medallion.PostgreSql", "src\Data\DistributedLocking\Masa.Contrib.Data.DistributedLocking.Medallion.PostgreSql\Masa.Contrib.Data.DistributedLocking.Medallion.PostgreSql.csproj", "{1B04884B-D903-42CD-A4EB-259068325653}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.Contrib.Data.DistributedLocking.Medallion.Redis", "src\Data\DistributedLocking\Masa.Contrib.Data.DistributedLocking.Medallion.Redis\Masa.Contrib.Data.DistributedLocking.Medallion.Redis.csproj", "{2D849FCE-7EF7-4932-8022-422F5B0F1AC8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Data.DistributedLocking.Medallion.MySql", "src\Data\DistributedLocking\Masa.Contrib.Data.DistributedLocking.Medallion.MySql\Masa.Contrib.Data.DistributedLocking.Medallion.MySql.csproj", "{91A0E44C-3F12-409B-8C2D-DA2689338D68}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.Contrib.Data.DistributedLocking.Medallion.PostgreSql", "src\Data\DistributedLocking\Masa.Contrib.Data.DistributedLocking.Medallion.PostgreSql\Masa.Contrib.Data.DistributedLocking.Medallion.PostgreSql.csproj", "{1B04884B-D903-42CD-A4EB-259068325653}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Data.DistributedLocking.Medallion.Oracle", "src\Data\DistributedLocking\Masa.Contrib.Data.DistributedLocking.Medallion.Oracle\Masa.Contrib.Data.DistributedLocking.Medallion.Oracle.csproj", "{424FDF4D-198B-46FB-B1A9-F229EB80B195}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.Contrib.Data.DistributedLocking.Medallion.MySql", "src\Data\DistributedLocking\Masa.Contrib.Data.DistributedLocking.Medallion.MySql\Masa.Contrib.Data.DistributedLocking.Medallion.MySql.csproj", "{91A0E44C-3F12-409B-8C2D-DA2689338D68}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Data.DistributedLocking.Medallion.Azure", "src\Data\DistributedLocking\Masa.Contrib.Data.DistributedLocking.Medallion.Azure\Masa.Contrib.Data.DistributedLocking.Medallion.Azure.csproj", "{D77650B4-A242-4686-820E-3863931E0229}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.Contrib.Data.DistributedLocking.Medallion.Oracle", "src\Data\DistributedLocking\Masa.Contrib.Data.DistributedLocking.Medallion.Oracle\Masa.Contrib.Data.DistributedLocking.Medallion.Oracle.csproj", "{424FDF4D-198B-46FB-B1A9-F229EB80B195}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Data.DistributedLocking.Medallion.ZooKeeper", "src\Data\DistributedLocking\Masa.Contrib.Data.DistributedLocking.Medallion.ZooKeeper\Masa.Contrib.Data.DistributedLocking.Medallion.ZooKeeper.csproj", "{083933A9-5402-453E-851F-9095BFBB57FE}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.Contrib.Data.DistributedLocking.Medallion.Azure", "src\Data\DistributedLocking\Masa.Contrib.Data.DistributedLocking.Medallion.Azure\Masa.Contrib.Data.DistributedLocking.Medallion.Azure.csproj", "{D77650B4-A242-4686-820E-3863931E0229}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Data.DistributedLocking.Medallion.FileSystem", "src\Data\DistributedLocking\Masa.Contrib.Data.DistributedLocking.Medallion.FileSystem\Masa.Contrib.Data.DistributedLocking.Medallion.FileSystem.csproj", "{1AD38027-C406-4FA4-B8FD-23E6336C2C4C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.Contrib.Data.DistributedLocking.Medallion.ZooKeeper", "src\Data\DistributedLocking\Masa.Contrib.Data.DistributedLocking.Medallion.ZooKeeper\Masa.Contrib.Data.DistributedLocking.Medallion.ZooKeeper.csproj", "{083933A9-5402-453E-851F-9095BFBB57FE}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Data.DistributedLocking.Medallion.WaitHandles", "src\Data\DistributedLocking\Masa.Contrib.Data.DistributedLocking.Medallion.WaitHandles\Masa.Contrib.Data.DistributedLocking.Medallion.WaitHandles.csproj", "{8C5D0C99-59D7-4E79-9AE4-AF7AA7F2DB3D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.Contrib.Data.DistributedLocking.Medallion.FileSystem", "src\Data\DistributedLocking\Masa.Contrib.Data.DistributedLocking.Medallion.FileSystem\Masa.Contrib.Data.DistributedLocking.Medallion.FileSystem.csproj", "{1AD38027-C406-4FA4-B8FD-23E6336C2C4C}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Identity", "Identity", "{5F25960E-646D-4EA6-A648-3CAD284B6E38}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.Contrib.Data.DistributedLocking.Medallion.WaitHandles", "src\Data\DistributedLocking\Masa.Contrib.Data.DistributedLocking.Medallion.WaitHandles\Masa.Contrib.Data.DistributedLocking.Medallion.WaitHandles.csproj", "{8C5D0C99-59D7-4E79-9AE4-AF7AA7F2DB3D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Identity.IdentityModel", "src\Identity\Masa.Contrib.Identity.IdentityModel\Masa.Contrib.Identity.IdentityModel.csproj", "{AA7876FF-3EF9-40EC-B5FF-66AB748DB93E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -963,22 +980,6 @@ Global {D8E85337-A779-48FC-B822-CE8A850661DC}.Release|Any CPU.Build.0 = Release|Any CPU {D8E85337-A779-48FC-B822-CE8A850661DC}.Release|x64.ActiveCfg = Release|Any CPU {D8E85337-A779-48FC-B822-CE8A850661DC}.Release|x64.Build.0 = Release|Any CPU - {2FD02408-DF1D-48E0-94F2-9910E76D8B6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2FD02408-DF1D-48E0-94F2-9910E76D8B6E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2FD02408-DF1D-48E0-94F2-9910E76D8B6E}.Debug|x64.ActiveCfg = Debug|Any CPU - {2FD02408-DF1D-48E0-94F2-9910E76D8B6E}.Debug|x64.Build.0 = Debug|Any CPU - {2FD02408-DF1D-48E0-94F2-9910E76D8B6E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2FD02408-DF1D-48E0-94F2-9910E76D8B6E}.Release|Any CPU.Build.0 = Release|Any CPU - {2FD02408-DF1D-48E0-94F2-9910E76D8B6E}.Release|x64.ActiveCfg = Release|Any CPU - {2FD02408-DF1D-48E0-94F2-9910E76D8B6E}.Release|x64.Build.0 = Release|Any CPU - {A0185D9A-69AB-4668-97F6-132C7D0947AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A0185D9A-69AB-4668-97F6-132C7D0947AA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A0185D9A-69AB-4668-97F6-132C7D0947AA}.Debug|x64.ActiveCfg = Debug|Any CPU - {A0185D9A-69AB-4668-97F6-132C7D0947AA}.Debug|x64.Build.0 = Debug|Any CPU - {A0185D9A-69AB-4668-97F6-132C7D0947AA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A0185D9A-69AB-4668-97F6-132C7D0947AA}.Release|Any CPU.Build.0 = Release|Any CPU - {A0185D9A-69AB-4668-97F6-132C7D0947AA}.Release|x64.ActiveCfg = Release|Any CPU - {A0185D9A-69AB-4668-97F6-132C7D0947AA}.Release|x64.Build.0 = Release|Any CPU {30DC35DF-9D86-443C-B26C-9053E6FCA434}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {30DC35DF-9D86-443C-B26C-9053E6FCA434}.Debug|Any CPU.Build.0 = Debug|Any CPU {30DC35DF-9D86-443C-B26C-9053E6FCA434}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -1011,14 +1012,70 @@ Global {32488758-25C9-4257-9B98-DAA034C19909}.Release|Any CPU.Build.0 = Release|Any CPU {32488758-25C9-4257-9B98-DAA034C19909}.Release|x64.ActiveCfg = Release|Any CPU {32488758-25C9-4257-9B98-DAA034C19909}.Release|x64.Build.0 = Release|Any CPU - {E08AF686-91D4-48B4-B5DF-90474D18E984}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E08AF686-91D4-48B4-B5DF-90474D18E984}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E08AF686-91D4-48B4-B5DF-90474D18E984}.Debug|x64.ActiveCfg = Debug|Any CPU - {E08AF686-91D4-48B4-B5DF-90474D18E984}.Debug|x64.Build.0 = Debug|Any CPU - {E08AF686-91D4-48B4-B5DF-90474D18E984}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E08AF686-91D4-48B4-B5DF-90474D18E984}.Release|Any CPU.Build.0 = Release|Any CPU - {E08AF686-91D4-48B4-B5DF-90474D18E984}.Release|x64.ActiveCfg = Release|Any CPU - {E08AF686-91D4-48B4-B5DF-90474D18E984}.Release|x64.Build.0 = Release|Any CPU + {4B94CAF6-134D-4F89-8F2D-72A4FB363B59}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4B94CAF6-134D-4F89-8F2D-72A4FB363B59}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4B94CAF6-134D-4F89-8F2D-72A4FB363B59}.Debug|x64.ActiveCfg = Debug|Any CPU + {4B94CAF6-134D-4F89-8F2D-72A4FB363B59}.Debug|x64.Build.0 = Debug|Any CPU + {4B94CAF6-134D-4F89-8F2D-72A4FB363B59}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4B94CAF6-134D-4F89-8F2D-72A4FB363B59}.Release|Any CPU.Build.0 = Release|Any CPU + {4B94CAF6-134D-4F89-8F2D-72A4FB363B59}.Release|x64.ActiveCfg = Release|Any CPU + {4B94CAF6-134D-4F89-8F2D-72A4FB363B59}.Release|x64.Build.0 = Release|Any CPU + {54936F20-EEFC-405B-8646-76F200A5C8F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {54936F20-EEFC-405B-8646-76F200A5C8F7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {54936F20-EEFC-405B-8646-76F200A5C8F7}.Debug|x64.ActiveCfg = Debug|Any CPU + {54936F20-EEFC-405B-8646-76F200A5C8F7}.Debug|x64.Build.0 = Debug|Any CPU + {54936F20-EEFC-405B-8646-76F200A5C8F7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {54936F20-EEFC-405B-8646-76F200A5C8F7}.Release|Any CPU.Build.0 = Release|Any CPU + {54936F20-EEFC-405B-8646-76F200A5C8F7}.Release|x64.ActiveCfg = Release|Any CPU + {54936F20-EEFC-405B-8646-76F200A5C8F7}.Release|x64.Build.0 = Release|Any CPU + {546EE1A2-DB6B-49D3-8919-33624FEF2498}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {546EE1A2-DB6B-49D3-8919-33624FEF2498}.Debug|Any CPU.Build.0 = Debug|Any CPU + {546EE1A2-DB6B-49D3-8919-33624FEF2498}.Debug|x64.ActiveCfg = Debug|Any CPU + {546EE1A2-DB6B-49D3-8919-33624FEF2498}.Debug|x64.Build.0 = Debug|Any CPU + {546EE1A2-DB6B-49D3-8919-33624FEF2498}.Release|Any CPU.ActiveCfg = Release|Any CPU + {546EE1A2-DB6B-49D3-8919-33624FEF2498}.Release|Any CPU.Build.0 = Release|Any CPU + {546EE1A2-DB6B-49D3-8919-33624FEF2498}.Release|x64.ActiveCfg = Release|Any CPU + {546EE1A2-DB6B-49D3-8919-33624FEF2498}.Release|x64.Build.0 = Release|Any CPU + {B603B92A-1203-4E28-9D15-2AF1CE4E9510}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B603B92A-1203-4E28-9D15-2AF1CE4E9510}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B603B92A-1203-4E28-9D15-2AF1CE4E9510}.Debug|x64.ActiveCfg = Debug|Any CPU + {B603B92A-1203-4E28-9D15-2AF1CE4E9510}.Debug|x64.Build.0 = Debug|Any CPU + {B603B92A-1203-4E28-9D15-2AF1CE4E9510}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B603B92A-1203-4E28-9D15-2AF1CE4E9510}.Release|Any CPU.Build.0 = Release|Any CPU + {B603B92A-1203-4E28-9D15-2AF1CE4E9510}.Release|x64.ActiveCfg = Release|Any CPU + {B603B92A-1203-4E28-9D15-2AF1CE4E9510}.Release|x64.Build.0 = Release|Any CPU + {FBF18906-7113-4036-BAEB-56E925F7D301}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FBF18906-7113-4036-BAEB-56E925F7D301}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FBF18906-7113-4036-BAEB-56E925F7D301}.Debug|x64.ActiveCfg = Debug|Any CPU + {FBF18906-7113-4036-BAEB-56E925F7D301}.Debug|x64.Build.0 = Debug|Any CPU + {FBF18906-7113-4036-BAEB-56E925F7D301}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FBF18906-7113-4036-BAEB-56E925F7D301}.Release|Any CPU.Build.0 = Release|Any CPU + {FBF18906-7113-4036-BAEB-56E925F7D301}.Release|x64.ActiveCfg = Release|Any CPU + {FBF18906-7113-4036-BAEB-56E925F7D301}.Release|x64.Build.0 = Release|Any CPU + {661A5C41-A5DE-45C9-A7CF-B59C2B9B23E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {661A5C41-A5DE-45C9-A7CF-B59C2B9B23E0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {661A5C41-A5DE-45C9-A7CF-B59C2B9B23E0}.Debug|x64.ActiveCfg = Debug|Any CPU + {661A5C41-A5DE-45C9-A7CF-B59C2B9B23E0}.Debug|x64.Build.0 = Debug|Any CPU + {661A5C41-A5DE-45C9-A7CF-B59C2B9B23E0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {661A5C41-A5DE-45C9-A7CF-B59C2B9B23E0}.Release|Any CPU.Build.0 = Release|Any CPU + {661A5C41-A5DE-45C9-A7CF-B59C2B9B23E0}.Release|x64.ActiveCfg = Release|Any CPU + {661A5C41-A5DE-45C9-A7CF-B59C2B9B23E0}.Release|x64.Build.0 = Release|Any CPU + {F2E1018A-F423-4782-BE9D-6169C669AD43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F2E1018A-F423-4782-BE9D-6169C669AD43}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F2E1018A-F423-4782-BE9D-6169C669AD43}.Debug|x64.ActiveCfg = Debug|Any CPU + {F2E1018A-F423-4782-BE9D-6169C669AD43}.Debug|x64.Build.0 = Debug|Any CPU + {F2E1018A-F423-4782-BE9D-6169C669AD43}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F2E1018A-F423-4782-BE9D-6169C669AD43}.Release|Any CPU.Build.0 = Release|Any CPU + {F2E1018A-F423-4782-BE9D-6169C669AD43}.Release|x64.ActiveCfg = Release|Any CPU + {F2E1018A-F423-4782-BE9D-6169C669AD43}.Release|x64.Build.0 = Release|Any CPU + {18634B69-0ED1-4C64-9735-4DFD2B2B0E9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {18634B69-0ED1-4C64-9735-4DFD2B2B0E9B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {18634B69-0ED1-4C64-9735-4DFD2B2B0E9B}.Debug|x64.ActiveCfg = Debug|Any CPU + {18634B69-0ED1-4C64-9735-4DFD2B2B0E9B}.Debug|x64.Build.0 = Debug|Any CPU + {18634B69-0ED1-4C64-9735-4DFD2B2B0E9B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {18634B69-0ED1-4C64-9735-4DFD2B2B0E9B}.Release|Any CPU.Build.0 = Release|Any CPU + {18634B69-0ED1-4C64-9735-4DFD2B2B0E9B}.Release|x64.ActiveCfg = Release|Any CPU + {18634B69-0ED1-4C64-9735-4DFD2B2B0E9B}.Release|x64.Build.0 = Release|Any CPU {338EA0ED-B7B2-44D8-9F34-235C484E3497}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {338EA0ED-B7B2-44D8-9F34-235C484E3497}.Debug|Any CPU.Build.0 = Debug|Any CPU {338EA0ED-B7B2-44D8-9F34-235C484E3497}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -1107,6 +1164,14 @@ Global {8C5D0C99-59D7-4E79-9AE4-AF7AA7F2DB3D}.Release|Any CPU.Build.0 = Release|Any CPU {8C5D0C99-59D7-4E79-9AE4-AF7AA7F2DB3D}.Release|x64.ActiveCfg = Release|Any CPU {8C5D0C99-59D7-4E79-9AE4-AF7AA7F2DB3D}.Release|x64.Build.0 = Release|Any CPU + {AA7876FF-3EF9-40EC-B5FF-66AB748DB93E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AA7876FF-3EF9-40EC-B5FF-66AB748DB93E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AA7876FF-3EF9-40EC-B5FF-66AB748DB93E}.Debug|x64.ActiveCfg = Debug|Any CPU + {AA7876FF-3EF9-40EC-B5FF-66AB748DB93E}.Debug|x64.Build.0 = Debug|Any CPU + {AA7876FF-3EF9-40EC-B5FF-66AB748DB93E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AA7876FF-3EF9-40EC-B5FF-66AB748DB93E}.Release|Any CPU.Build.0 = Release|Any CPU + {AA7876FF-3EF9-40EC-B5FF-66AB748DB93E}.Release|x64.ActiveCfg = Release|Any CPU + {AA7876FF-3EF9-40EC-B5FF-66AB748DB93E}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1217,17 +1282,23 @@ Global {E7987CBB-8DDD-4AC5-B522-653E2F457C85} = {6DB8780E-BA11-47CD-8FAB-D73A1F71B305} {AD427256-9686-4289-A635-1B387BD56D15} = {E6363F59-2BA4-4AA7-8578-C433A2C2567F} {2B644A8C-F0EE-4566-AB78-9E1C6D4185A3} = {38E6C400-90C0-493E-9266-C1602E229F1B} + {4995742C-033A-4147-89E7-7FFE7681C971} = {42DF7AAC-362C-48F4-B76A-BDEEEFF17CC9} + {B7F5651E-C4CB-413E-AF6E-420D1AFB7EA6} = {DC578D74-98F0-4F19-A230-CFA8DAEE0AF1} {DC50078D-D706-4CB9-A301-F47CB3F46007} = {6DB8780E-BA11-47CD-8FAB-D73A1F71B305} {E6363F59-2BA4-4AA7-8578-C433A2C2567F} = {38E6C400-90C0-493E-9266-C1602E229F1B} {D8E85337-A779-48FC-B822-CE8A850661DC} = {E6363F59-2BA4-4AA7-8578-C433A2C2567F} - {2FD02408-DF1D-48E0-94F2-9910E76D8B6E} = {DC578D74-98F0-4F19-A230-CFA8DAEE0AF1} - {8E9691A2-BBCA-4A0F-906D-61D159F78B3B} = {42DF7AAC-362C-48F4-B76A-BDEEEFF17CC9} - {A0185D9A-69AB-4668-97F6-132C7D0947AA} = {8E9691A2-BBCA-4A0F-906D-61D159F78B3B} {30DC35DF-9D86-443C-B26C-9053E6FCA434} = {DC578D74-98F0-4F19-A230-CFA8DAEE0AF1} {24E5BF57-33B6-4D5B-A32F-2F64D1A5954F} = {6DB8780E-BA11-47CD-8FAB-D73A1F71B305} {B15F4561-E511-42EA-A02E-F772BAF41E20} = {6DB8780E-BA11-47CD-8FAB-D73A1F71B305} {32488758-25C9-4257-9B98-DAA034C19909} = {E6363F59-2BA4-4AA7-8578-C433A2C2567F} - {E08AF686-91D4-48B4-B5DF-90474D18E984} = {38E6C400-90C0-493E-9266-C1602E229F1B} + {4B94CAF6-134D-4F89-8F2D-72A4FB363B59} = {B7F5651E-C4CB-413E-AF6E-420D1AFB7EA6} + {54936F20-EEFC-405B-8646-76F200A5C8F7} = {B7F5651E-C4CB-413E-AF6E-420D1AFB7EA6} + {546EE1A2-DB6B-49D3-8919-33624FEF2498} = {B7F5651E-C4CB-413E-AF6E-420D1AFB7EA6} + {B603B92A-1203-4E28-9D15-2AF1CE4E9510} = {B7F5651E-C4CB-413E-AF6E-420D1AFB7EA6} + {FBF18906-7113-4036-BAEB-56E925F7D301} = {4995742C-033A-4147-89E7-7FFE7681C971} + {661A5C41-A5DE-45C9-A7CF-B59C2B9B23E0} = {4995742C-033A-4147-89E7-7FFE7681C971} + {F2E1018A-F423-4782-BE9D-6169C669AD43} = {4995742C-033A-4147-89E7-7FFE7681C971} + {18634B69-0ED1-4C64-9735-4DFD2B2B0E9B} = {DC578D74-98F0-4F19-A230-CFA8DAEE0AF1} {07BD7788-9DC0-4BD0-9861-0C9AC13B4EB8} = {E33ADF54-4D35-49B7-BDA6-412587CA39FF} {338EA0ED-B7B2-44D8-9F34-235C484E3497} = {07BD7788-9DC0-4BD0-9861-0C9AC13B4EB8} {C74B04E6-6C6E-4DE0-BAF3-94224F422D60} = {07BD7788-9DC0-4BD0-9861-0C9AC13B4EB8} @@ -1240,6 +1311,8 @@ Global {083933A9-5402-453E-851F-9095BFBB57FE} = {07BD7788-9DC0-4BD0-9861-0C9AC13B4EB8} {1AD38027-C406-4FA4-B8FD-23E6336C2C4C} = {07BD7788-9DC0-4BD0-9861-0C9AC13B4EB8} {8C5D0C99-59D7-4E79-9AE4-AF7AA7F2DB3D} = {07BD7788-9DC0-4BD0-9861-0C9AC13B4EB8} + {5F25960E-646D-4EA6-A648-3CAD284B6E38} = {42DF7AAC-362C-48F4-B76A-BDEEEFF17CC9} + {AA7876FF-3EF9-40EC-B5FF-66AB748DB93E} = {5F25960E-646D-4EA6-A648-3CAD284B6E38} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {40383055-CC50-4600-AD9A-53C14F620D03} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/Masa.Contrib.Authentication.Oidc.Cache.Storage.csproj b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/Masa.Contrib.Authentication.Oidc.Cache.Storage.csproj new file mode 100644 index 000000000..0a314a09b --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/Masa.Contrib.Authentication.Oidc.Cache.Storage.csproj @@ -0,0 +1,22 @@ + + + + net6.0 + enable + enable + + $(WarningsAsErrors);CS8600;CS8601;CS8602;CS8603;CS8604;CS8609;CS8610;CS8614;CS8616;CS8618;CS8619;CS8620;CS8622;CS8625 + + + + + + + + + + + + + + diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/ServiceCollectionExtensions.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/ServiceCollectionExtensions.cs new file mode 100644 index 000000000..850232a68 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/ServiceCollectionExtensions.cs @@ -0,0 +1,18 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.Cache.Storage; + +public static class ServiceCollectionExtensions +{ + public static IServiceCollection AddOidcCacheStorage(this IServiceCollection services, RedisConfigurationOptions options) + { + services.AddOidcCache(options); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + + return services; + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/Stores/ClientStore.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/Stores/ClientStore.cs new file mode 100644 index 000000000..bd2ad9e71 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/Stores/ClientStore.cs @@ -0,0 +1,22 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.Cache.Storage.Stores; + +public class ClientStore : IClientStore +{ + IClientCache _clientCache; + + public ClientStore(IClientCache clientCache) + { + _clientCache = clientCache; + } + + public async Task FindClientByIdAsync(string clientId) + { + ArgumentNullException.ThrowIfNull(clientId); + + var client = await _clientCache.GetAsync(clientId); + return client; + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/Stores/DeviceFlowStore.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/Stores/DeviceFlowStore.cs new file mode 100644 index 000000000..2e6f65101 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/Stores/DeviceFlowStore.cs @@ -0,0 +1,32 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.Cache.Storage.Stores; + +public class DeviceFlowStore : IDeviceFlowStore +{ + public Task FindByDeviceCodeAsync(string deviceCode) + { + throw new NotImplementedException(); + } + + public Task FindByUserCodeAsync(string userCode) + { + throw new NotImplementedException(); + } + + public Task RemoveByDeviceCodeAsync(string deviceCode) + { + throw new NotImplementedException(); + } + + public Task StoreDeviceAuthorizationAsync(string deviceCode, string userCode, DeviceCodeModel data) + { + throw new NotImplementedException(); + } + + public Task UpdateByUserCodeAsync(string userCode, DeviceCodeModel data) + { + throw new NotImplementedException(); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/Stores/PersistedGrantStore.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/Stores/PersistedGrantStore.cs new file mode 100644 index 000000000..ebab3a890 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/Stores/PersistedGrantStore.cs @@ -0,0 +1,32 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.Cache.Storage.Stores; + +public class PersistedGrantStore : IPersistedGrantStore +{ + public Task> GetAllAsync(PersistedGrantFilter filter) + { + throw new NotImplementedException(); + } + + public Task GetAsync(string key) + { + throw new NotImplementedException(); + } + + public Task RemoveAllAsync(PersistedGrantFilter filter) + { + throw new NotImplementedException(); + } + + public Task RemoveAsync(string key) + { + throw new NotImplementedException(); + } + + public Task StoreAsync(PersistedGrantModel grant) + { + throw new NotImplementedException(); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/Stores/ResourceStore.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/Stores/ResourceStore.cs new file mode 100644 index 000000000..856805159 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/Stores/ResourceStore.cs @@ -0,0 +1,58 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.Cache.Storage.Stores; + +public class ResourceStore : IResourceStore +{ + IIdentityResourceCache _identityResourceCache; + IApiResourceCache _apiResourceCache; + IApiScopeCache _apiScopeCache; + + public ResourceStore(IIdentityResourceCache identityResourceCache, IApiResourceCache apiResourceCache, IApiScopeCache apiScopeCache) + { + _identityResourceCache = identityResourceCache; + _apiResourceCache = apiResourceCache; + _apiScopeCache = apiScopeCache; + } + + public async Task> FindApiResourcesByNameAsync(IEnumerable apiResourceNames) + { + ArgumentNullException.ThrowIfNull(apiResourceNames); + + return await _apiResourceCache.GetListAsync(apiResourceNames); + } + + public async Task> FindApiResourcesByScopeNameAsync(IEnumerable scopeNames) + { + ArgumentNullException.ThrowIfNull(scopeNames); + + var apiResources = await _apiResourceCache.GetListAsync(); + return apiResources.Where(apiResource => apiResource.Scopes?.Any(scope => scopeNames.Contains(scope)) is true); + } + + public async Task> FindApiScopesByNameAsync(IEnumerable scopeNames) + { + ArgumentNullException.ThrowIfNull(scopeNames); + + var apiScopes = await _apiScopeCache.GetListAsync(scopeNames); + return apiScopes; + } + + public async Task> FindIdentityResourcesByScopeNameAsync(IEnumerable scopeNames) + { + ArgumentNullException.ThrowIfNull(scopeNames); + + var identityResources = await _identityResourceCache.GetListAsync(scopeNames); + return identityResources; + } + + public async Task GetAllResourcesAsync() + { + var identityResources = await _identityResourceCache.GetListAsync(); + var apiScopes = await _apiScopeCache.GetListAsync(); + var apiResources = await _apiResourceCache.GetListAsync(); + var resources = new ResourcesModel(identityResources, apiResources, apiScopes); + return resources; + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/_Imports.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/_Imports.cs new file mode 100644 index 000000000..111ca2413 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache.Storage/_Imports.cs @@ -0,0 +1,9 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +global using Masa.BuildingBlocks.Authentication.Oidc.Cache.Caches; +global using Masa.BuildingBlocks.Authentication.Oidc.Models.Models; +global using Masa.BuildingBlocks.Authentication.Oidc.Storage.Stores; +global using Masa.Contrib.Authentication.Oidc.Cache.Storage.Stores; +global using Microsoft.Extensions.DependencyInjection; +global using Masa.Utils.Caching.Redis.Models; diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Caches/ApiResourceCache.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Caches/ApiResourceCache.cs new file mode 100644 index 000000000..078a867d0 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Caches/ApiResourceCache.cs @@ -0,0 +1,72 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.Cache.Caches; + +public class ApiResourceCache : IApiResourceCache +{ + IMemoryCacheClient _memoryCacheClient; + + public ApiResourceCache(IMemoryCacheClient memoryCacheClient) + { + _memoryCacheClient = memoryCacheClient; + } + + public async Task> GetListAsync(IEnumerable names) + { + var keys = names.Select(name => $"{CacheKeyConstants.API_RESOURCE_KEY}_{name}"); + var apiResources = await _memoryCacheClient.GetListAsync(keys.ToArray()); + return apiResources.Where(i => i is not null).ToList()!; + } + + public async Task> GetListAsync() + { + var apiResources = await _memoryCacheClient.GetAsync>(CacheKeyConstants.API_RESOURCE_KEY) ?? new(); + return apiResources; + } + + public async Task SetAsync(ApiResource apiResource) + { + var model = apiResource.ToModel(); + string key = $"{CacheKeyConstants.API_RESOURCE_KEY}_{apiResource.Name}"; + await _memoryCacheClient.SetAsync(key, model); + // update list cache + var list = await GetListAsync(); + list.Set(model, item => item.Name); + await UpdateListAsync(list); + } + + public async Task SetRangeAsync(IEnumerable apiResources) + { + var models = apiResources.Select(apiScope => apiScope.ToModel()); + var map = models.ToDictionary(model => $"{CacheKeyConstants.API_RESOURCE_KEY}_{model.Name}", model => model); + await _memoryCacheClient.SetListAsync(map); + // update list cache + var list = await GetListAsync(); + list.SetRange(models, item => item.Name); + await UpdateListAsync(list); + } + + public async Task RemoveAsync(ApiResource apiResource) + { + string key = $"{CacheKeyConstants.API_RESOURCE_KEY}_{apiResource.Name}"; + await _memoryCacheClient.RemoveAsync(key); + // update list cache + var list = await GetListAsync(); + list.Remove(item => item.Name == apiResource.Name); + await UpdateListAsync(list); + } + + public async Task ResetAsync(IEnumerable apiResources) + { + var models = apiResources.Select(apiScope => apiScope.ToModel()); + await UpdateListAsync(models); + var map = models.ToDictionary(model => $"{CacheKeyConstants.API_RESOURCE_KEY}_{model.Name}", model => model); + await _memoryCacheClient.SetListAsync(map); + } + + private async Task UpdateListAsync(IEnumerable models) + { + await _memoryCacheClient.SetAsync(CacheKeyConstants.API_RESOURCE_KEY, models); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Caches/ApiScopeCache.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Caches/ApiScopeCache.cs new file mode 100644 index 000000000..42e8b9487 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Caches/ApiScopeCache.cs @@ -0,0 +1,72 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.Cache.Caches; + +public class ApiScopeCache : IApiScopeCache +{ + IMemoryCacheClient _memoryCacheClient; + + public ApiScopeCache(IMemoryCacheClient memoryCacheClient) + { + _memoryCacheClient = memoryCacheClient; + } + + public async Task> GetListAsync(IEnumerable names) + { + var keys = names.Select(name => $"{CacheKeyConstants.API_SCOPE_KEY}_{name}"); + var apiScopes = await _memoryCacheClient.GetListAsync(keys.ToArray()); + return apiScopes.Where(i => i is not null).ToList()!; + } + + public async Task> GetListAsync() + { + var ApiScopes = await _memoryCacheClient.GetAsync>(CacheKeyConstants.API_SCOPE_KEY) ?? new(); + return ApiScopes; + } + + public async Task SetAsync(ApiScope apiScope) + { + string key = $"{CacheKeyConstants.API_SCOPE_KEY}_{apiScope.Name}"; + var model = apiScope.ToModel(); + await _memoryCacheClient.SetAsync(key, model); + // update list cache + var list = await GetListAsync(); + list.Set(model, item => item.Name); + await UpdateListAsync(list); + } + + public async Task SetRangeAsync(IEnumerable apiScopes) + { + var models = apiScopes.Select(apiScope => apiScope.ToModel()); + var data = models.ToDictionary(model => $"{CacheKeyConstants.API_SCOPE_KEY}_{model.Name}", model => model); + await _memoryCacheClient.SetListAsync(data); + // update list cache + var list = await GetListAsync(); + list.SetRange(models, item => item.Name); + await UpdateListAsync(list); + } + + public async Task RemoveAsync(ApiScope apiScope) + { + string key = $"{CacheKeyConstants.API_SCOPE_KEY}_{apiScope.Name}"; + await _memoryCacheClient.RemoveAsync(key); + // update list cache + var list = await GetListAsync(); + list.Remove(item => item.Name == apiScope.Name); + await UpdateListAsync(list); + } + + public async Task ResetAsync(IEnumerable apiScopes) + { + var models = apiScopes.Select(apiScope => apiScope.ToModel()); + await UpdateListAsync(models); + var map = models.ToDictionary(model => $"{CacheKeyConstants.API_SCOPE_KEY}_{model.Name}", model => model); + await _memoryCacheClient.SetListAsync(map); + } + + private async Task UpdateListAsync(IEnumerable models) + { + await _memoryCacheClient.SetAsync(CacheKeyConstants.API_SCOPE_KEY, models); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Caches/ClientCache.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Caches/ClientCache.cs new file mode 100644 index 000000000..6ca0e0a60 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Caches/ClientCache.cs @@ -0,0 +1,38 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.Cache.Caches; + +public class ClientCache : IClientCache +{ + IMemoryCacheClient _memoryCacheClient; + + public ClientCache(IMemoryCacheClient memoryCacheClient) + { + _memoryCacheClient = memoryCacheClient; + } + + public async Task GetAsync(string clientId) + { + string key = $"{CacheKeyConstants.CLIENT_KEY}_{clientId}"; + return await _memoryCacheClient.GetAsync(key); + } + + public async Task SetAsync(Client client) + { + string key = $"{CacheKeyConstants.CLIENT_KEY}_{client.ClientId}"; + await _memoryCacheClient.SetAsync(key, client.ToModel()); + } + + public async Task RemoveAsync(Client client) + { + string key = $"{CacheKeyConstants.CLIENT_KEY}_{client.ClientId}"; + await _memoryCacheClient.RemoveAsync(key); + } + + public async Task SetRangeAsync(IEnumerable clients) + { + var data = clients.ToDictionary(client => $"{CacheKeyConstants.CLIENT_KEY}_{client.ClientId}", client => client.ToModel()); + await _memoryCacheClient.SetListAsync(data); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Caches/IdentityResourceCache.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Caches/IdentityResourceCache.cs new file mode 100644 index 000000000..f05879525 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Caches/IdentityResourceCache.cs @@ -0,0 +1,72 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.Cache.Caches; + +public class IdentityResourceCache : IIdentityResourceCache +{ + IMemoryCacheClient _memoryCacheClient; + + public IdentityResourceCache(IMemoryCacheClient memoryCacheClient) + { + _memoryCacheClient = memoryCacheClient; + } + + public async Task> GetListAsync(IEnumerable names) + { + var keys = names.Select(name => $"{CacheKeyConstants.IDENTITY_RESOURCE_KEY}_{name}"); + var identityResources = await _memoryCacheClient.GetListAsync(keys.ToArray()); + return identityResources.Where(identityResource => identityResource is not null).ToList()!; + } + + public async Task> GetListAsync() + { + var identityResources = await _memoryCacheClient.GetAsync>(CacheKeyConstants.IDENTITY_RESOURCE_KEY) ?? new(); + return identityResources; + } + + public async Task SetAsync(IdentityResource identityResource) + { + string key = $"{CacheKeyConstants.IDENTITY_RESOURCE_KEY}_{identityResource.Name}"; + var model = identityResource.ToModel(); + await _memoryCacheClient.SetAsync(key, model); + // update list cache + var list = await GetListAsync(); + list.Set(model, item => item.Name); + await UpdateListAsync(list); + } + + public async Task SetRangeAsync(IEnumerable identityResources) + { + var models = identityResources.Select(identityResource => identityResource.ToModel()); + var map = models.ToDictionary(model => $"{CacheKeyConstants.IDENTITY_RESOURCE_KEY}_{model.Name}", model => model); + await _memoryCacheClient.SetListAsync(map); + // update list cache + var list = await GetListAsync(); + list.SetRange(models, item => item.Name); + await UpdateListAsync(list); + } + + public async Task RemoveAsync(IdentityResource identityResource) + { + string key = $"{CacheKeyConstants.IDENTITY_RESOURCE_KEY}_{identityResource.Name}"; + await _memoryCacheClient.RemoveAsync(key); + // update list cache + var list = await GetListAsync(); + list.Remove(item => item.Name == identityResource.Name); + await UpdateListAsync(list); + } + + public async Task ResetAsync(IEnumerable identityResources) + { + var models = identityResources.Select(identityResource => identityResource.ToModel()); + await UpdateListAsync(models); + var data = models.ToDictionary(model => $"{CacheKeyConstants.IDENTITY_RESOURCE_KEY}_{model.Name}", model => model); + await _memoryCacheClient.SetListAsync(data); + } + + private async Task UpdateListAsync(IEnumerable models) + { + await _memoryCacheClient.SetAsync(CacheKeyConstants.IDENTITY_RESOURCE_KEY, models); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Masa.Contrib.Authentication.Oidc.Cache.csproj b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Masa.Contrib.Authentication.Oidc.Cache.csproj new file mode 100644 index 000000000..7521d570c --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Masa.Contrib.Authentication.Oidc.Cache.csproj @@ -0,0 +1,18 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Models/CacheKeyConstants.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Models/CacheKeyConstants.cs new file mode 100644 index 000000000..c5d9e6a1e --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Models/CacheKeyConstants.cs @@ -0,0 +1,12 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.Cache.Models; + +public static class CacheKeyConstants +{ + public const string CLIENT_KEY = "oidc_client"; + public const string API_RESOURCE_KEY = "oidc_apiResource"; + public const string API_SCOPE_KEY = "oidc_apiScope"; + public const string IDENTITY_RESOURCE_KEY = "oidc_identityResource"; +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Models/Mapper.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Models/Mapper.cs new file mode 100644 index 000000000..93b9d1c08 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Models/Mapper.cs @@ -0,0 +1,105 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.Cache.Models; + +public static class Mapper +{ + public static ApiScopeModel ToModel(this ApiScope apiScope) + { + return new ApiScopeModel(apiScope.Name, apiScope.DisplayName, apiScope.UserClaims.Select(uc => uc.UserClaim.Name).ToList()) + { + Required = apiScope.Required, + Emphasize = apiScope.Emphasize, + Enabled = apiScope.Enabled, + Description = apiScope.Description, + Properties = apiScope.Properties.ToDictionary(p => p.Key, p => p.Value), + ShowInDiscoveryDocument = apiScope.ShowInDiscoveryDocument, + }; + } + + public static IdentityResourceModel ToModel(this IdentityResource identityResource) + { + return new IdentityResourceModel(identityResource.Name, identityResource.DisplayName, identityResource.UserClaims.Select(uc => uc.UserClaim.Name).ToList()) + { + Required = identityResource.Required, + Emphasize = identityResource.Emphasize, + Enabled = identityResource.Enabled, + Description = identityResource.Description, + Properties = identityResource.Properties.ToDictionary(p => p.Key, p => p.Value), + ShowInDiscoveryDocument = identityResource.ShowInDiscoveryDocument, + }; + } + + public static ApiResourceModel ToModel(this ApiResource apiResource) + { + return new ApiResourceModel(apiResource.Name, apiResource.DisplayName, apiResource.UserClaims.Select(uc => uc.UserClaim.Name).ToList()) + { + Scopes = apiResource.ApiScopes.Select(a => a.ApiScope.Name).ToList(), + ApiSecrets = apiResource.Secrets.Select(s => new SecretModel(s.Value, s.Description, s.Expiration)).ToList(), + AllowedAccessTokenSigningAlgorithms = Convert(apiResource.AllowedAccessTokenSigningAlgorithms), + Enabled = apiResource.Enabled, + Description = apiResource.Description, + ShowInDiscoveryDocument = apiResource.ShowInDiscoveryDocument, + }; + + ICollection Convert(string sourceMember) + { + var list = new HashSet(); + if (!string.IsNullOrWhiteSpace(sourceMember)) + { + sourceMember = sourceMember.Trim(); + foreach (var item in sourceMember.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Distinct()) + { + list.Add(item); + } + } + return list; + } + } + + public static ClientModel ToModel(this Client client) + { + return new ClientModel(client.ClientId.ToString(), client.ClientName, client.Description, client.ClientUri, client.LogoUri, client.RedirectUris.Select(r => r.RedirectUri), client.PostLogoutRedirectUris.Select(p => p.PostLogoutRedirectUri), client.AllowedGrantTypes.Select(a => a.GrantType), client.AllowedScopes.Select(a => a.Scope)) + { + Enabled = client.Enabled, + ProtocolType = client.ProtocolType, + RequireConsent = client.RequireConsent, + AllowRememberConsent = client.AllowRememberConsent, + AlwaysIncludeUserClaimsInIdToken = client.AlwaysIncludeUserClaimsInIdToken, + AllowPlainTextPkce = client.AllowPlainTextPkce, + RequireRequestObject = client.RequireRequestObject, + RequirePkce = client.RequirePkce, + FrontChannelLogoutUri = client.FrontChannelLogoutUri, + FrontChannelLogoutSessionRequired = client.FrontChannelLogoutSessionRequired, + BackChannelLogoutUri = client.BackChannelLogoutUri, + BackChannelLogoutSessionRequired = client.BackChannelLogoutSessionRequired, + AllowOfflineAccess = client.AllowOfflineAccess, + IdentityTokenLifetime = client.IdentityTokenLifetime, + AccessTokenLifetime = client.AccessTokenLifetime, + AuthorizationCodeLifetime = client.AuthorizationCodeLifetime, + ConsentLifetime = client.ConsentLifetime, + AbsoluteRefreshTokenLifetime = client.AbsoluteRefreshTokenLifetime, + SlidingRefreshTokenLifetime = client.SlidingRefreshTokenLifetime, + UpdateAccessTokenClaimsOnRefresh = client.UpdateAccessTokenClaimsOnRefresh, + EnableLocalLogin = client.EnableLocalLogin, + AlwaysSendClientClaims = client.AlwaysSendClientClaims, + Claims = client.Claims.Select(c => new ClientClaimModel(c.Type, c.Value)).ToList(), + AllowedCorsOrigins = client.AllowedCorsOrigins.Select(a => a.Origin).ToList(), + Properties = client.Properties.ToDictionary(p => p.Key, p => p.Value), + IdentityProviderRestrictions = client.IdentityProviderRestrictions.Select(i => i.Provider).ToList(), + AllowAccessTokensViaBrowser = client.AllowAccessTokensViaBrowser, + IncludeJwtId = client.IncludeJwtId, + AccessTokenType = (AccessTokenType)client.AccessTokenType, + DeviceCodeLifetime = client.DeviceCodeLifetime, + UserSsoLifetime = client.UserSsoLifetime, + RefreshTokenExpiration = (TokenExpiration)client.RefreshTokenExpiration, + RefreshTokenUsage = (TokenUsage)client.RefreshTokenUsage, + ClientClaimsPrefix = client.ClientClaimsPrefix, + PairWiseSubjectSalt = client.PairWiseSubjectSalt, + UserCodeType = client.UserCodeType, + ClientSecrets = client.ClientSecrets.Select(s => new SecretModel(s.Type, s.Value)).ToList(), + AllowedIdentityTokenSigningAlgorithms = client.AllowedIdentityTokenSigningAlgorithms.Split(",", StringSplitOptions.RemoveEmptyEntries).ToList(), + }; + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/ServiceCollectionExtensions.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/ServiceCollectionExtensions.cs new file mode 100644 index 000000000..a663238b9 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/ServiceCollectionExtensions.cs @@ -0,0 +1,18 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.Cache; + +public static class ServiceCollectionExtensions +{ + public static IServiceCollection AddOidcCache(this IServiceCollection services, RedisConfigurationOptions options) + { + services.AddMasaRedisCache(options).AddMasaMemoryCache(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + + return services; + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Utils/CollectionExtensions.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Utils/CollectionExtensions.cs new file mode 100644 index 000000000..f4f63f068 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/Utils/CollectionExtensions.cs @@ -0,0 +1,52 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.Cache.Utils; + +public static class CollectionExtensions +{ + public static void Set(this ICollection collection, T data, Func keySelector) + { + collection.Remove(data, keySelector); + collection.Add(data); + } + + public static void SetRange(this ICollection collection, IEnumerable datas, Func keySelector) + { + collection.RemoveRange(datas, keySelector); + foreach (var data in datas) + { + collection.Add(data); + } + } + + public static void Remove(this ICollection collection, T data, Func keySelector) + { + var oldData = collection.FirstOrDefault(item => keySelector(item).Equals(keySelector(data))); + if (oldData is not null) collection.Remove(oldData); + } + + public static void RemoveRange(this ICollection collection, IEnumerable datas, Func keySelector) + { + var oldDatas = collection.Where(item => datas.Any(data => keySelector(data).Equals(keySelector(item)))); + if (oldDatas.Count() > 0) + { + foreach (var oldData in oldDatas) + { + collection.Remove(oldData); + } + } + } + + public static void Remove(this ICollection collection, Func condition) + { + var datas = collection.Where(condition); + if(datas.Count() > 0) + { + foreach (var data in datas) + { + collection.Remove(data); + } + } + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/_Imports.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/_Imports.cs new file mode 100644 index 000000000..2f99c42d4 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.Cache/_Imports.cs @@ -0,0 +1,15 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +global using Masa.BuildingBlocks.Authentication.Oidc.Cache.Caches; +global using Masa.BuildingBlocks.Authentication.Oidc.Domain.Entities; +global using Masa.BuildingBlocks.Authentication.Oidc.Models.Enums; +global using Masa.BuildingBlocks.Authentication.Oidc.Models.Models; +global using Masa.Contrib.Authentication.Oidc.Cache.Caches; +global using Masa.Contrib.Authentication.Oidc.Cache.Models; +global using Masa.Contrib.Authentication.Oidc.Cache.Utils; +global using Masa.Utils.Caching.DistributedMemory.DependencyInjection; +global using Masa.Utils.Caching.DistributedMemory.Interfaces; +global using Masa.Utils.Caching.Redis.DependencyInjection; +global using Masa.Utils.Caching.Redis.Models; +global using Microsoft.Extensions.DependencyInjection; diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Caches/SyncCache.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Caches/SyncCache.cs new file mode 100644 index 000000000..152c1fce4 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Caches/SyncCache.cs @@ -0,0 +1,98 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.Caches; + +public class SyncCache +{ + IClientCache _clientCache; + IApiResourceCache _apiResourceCache; + IApiScopeCache _apiScopeCache; + IIdentityResourceCache _identityResourceCache; + OidcDbContext _context; + + public SyncCache(IClientCache clientCache, IApiResourceCache apiResourceCache, IApiScopeCache apiScopeCache, IIdentityResourceCache identityResourceCache, OidcDbContext context) + { + _clientCache = clientCache; + _apiResourceCache = apiResourceCache; + _apiScopeCache = apiScopeCache; + _identityResourceCache = identityResourceCache; + _context = context; + } + + internal async Task SyncApiResourceCacheAsync(int id) + { + var apiResource = await ApiResourceQuery().FirstOrDefaultAsync(apiResource => apiResource.Id == id); + if (apiResource is null) return; + await _apiResourceCache.SetAsync(apiResource); + } + + internal async Task SyncApiScopeCacheAsync(int id) + { + var apiScope = await ApiScopeQuery().FirstOrDefaultAsync(apiScope => apiScope.Id == id); + if (apiScope is null) return; + await _apiScopeCache.SetAsync(apiScope); + } + + internal async Task SyncIdentityResourceCacheAsync(params int[] ids) + { + var identityResources = await IdentityResourceQuery().Where(idrs => ids.Contains(idrs.Id)).ToListAsync(); + if (identityResources.Count < 0) return; + await _identityResourceCache.SetRangeAsync(identityResources); + } + + internal async Task RemoveApiResourceCacheAsync(ApiResource apiResource) + { + await _apiResourceCache.RemoveAsync(apiResource); + } + + internal async Task RemoveApiScopeCacheAsync(ApiScope apiScope) + { + await _apiScopeCache.RemoveAsync(apiScope); + } + + internal async Task RemoveIdentityResourceCacheAsync(IdentityResource identityResource) + { + await _identityResourceCache.RemoveAsync(identityResource); + } + + private IQueryable ClientQuery() + { + return _context.Set() + .Include(c => c.AllowedGrantTypes) + .Include(c => c.RedirectUris) + .Include(c => c.PostLogoutRedirectUris) + .Include(c => c.Properties) + .Include(c => c.Claims) + .Include(c => c.IdentityProviderRestrictions) + .Include(c => c.AllowedCorsOrigins) + .Include(c => c.ClientSecrets) + .Include(c => c.AllowedScopes); + } + + private IQueryable IdentityResourceQuery() + { + return _context.Set() + .Include(idrs => idrs.UserClaims) + .ThenInclude(uc => uc.UserClaim) + .Include(idrs => idrs.Properties); + } + + private IQueryable ApiScopeQuery() + { + return _context.Set() + .Include(apiScope => apiScope.UserClaims) + .ThenInclude(apiScope => apiScope.UserClaim) + .Include(apiScope => apiScope.Properties); + } + + private IQueryable ApiResourceQuery() + { + return _context.Set() + .Include(apiResource => apiResource.UserClaims) + .ThenInclude(userClaim => userClaim.UserClaim) + .Include(apiResource => apiResource.Properties) + .Include(apiResource => apiResource.ApiScopes) + .ThenInclude(apiScope => apiScope.ApiScope); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/DbContexts/OidcDbContext.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/DbContexts/OidcDbContext.cs new file mode 100644 index 000000000..3165b482b --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/DbContexts/OidcDbContext.cs @@ -0,0 +1,17 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.DbContexts; + +public class OidcDbContext : DbContext +{ + public OidcDbContext(DbContextOptions options) : base(options) + { + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.HasDefaultSchema("oidc"); + modelBuilder.ApplyConfigurationsFromAssembly(typeof(OidcDbContext).Assembly); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiResourceClaimEntityTypeConfiguration.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiResourceClaimEntityTypeConfiguration.cs new file mode 100644 index 000000000..1b1e4ee88 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiResourceClaimEntityTypeConfiguration.cs @@ -0,0 +1,12 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.EntityConfigurations; + +public class ApiResourceClaimEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(x => x.Id); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiResourceEntityTypeConfiguration.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiResourceEntityTypeConfiguration.cs new file mode 100644 index 000000000..f4acbda1c --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiResourceEntityTypeConfiguration.cs @@ -0,0 +1,20 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.EntityConfigurations; + +public class ApiResourceEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.Property(x => x.Name).HasMaxLength(200).IsRequired(); + builder.Property(x => x.DisplayName).HasMaxLength(200); + builder.Property(x => x.Description).HasMaxLength(1000); + builder.Property(x => x.AllowedAccessTokenSigningAlgorithms).HasMaxLength(100); + builder.HasIndex(x => x.Name).IsUnique().HasFilter("[IsDeleted] = 0"); + builder.HasMany(x => x.Secrets).WithOne(x => x.ApiResource).HasForeignKey(x => x.ApiResourceId).OnDelete(DeleteBehavior.Cascade); + builder.HasMany(x => x.ApiScopes).WithOne(x => x.ApiResource).HasForeignKey(x => x.ApiResourceId).IsRequired().OnDelete(DeleteBehavior.Cascade); + builder.HasMany(x => x.UserClaims).WithOne(x => x.ApiResource).HasForeignKey(x => x.ApiResourceId).OnDelete(DeleteBehavior.Cascade); + builder.HasMany(x => x.Properties).WithOne(x => x.ApiResource).HasForeignKey(x => x.ApiResourceId).OnDelete(DeleteBehavior.Cascade); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiResourcePropertyEntityTypeConfiguration.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiResourcePropertyEntityTypeConfiguration.cs new file mode 100644 index 000000000..6348fd9de --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiResourcePropertyEntityTypeConfiguration.cs @@ -0,0 +1,13 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.EntityConfigurations; + +public class ApiResourcePropertyEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.Property(x => x.Key).HasMaxLength(250).IsRequired(); + builder.Property(x => x.Value).HasMaxLength(2000).IsRequired(); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiResourceScopeEntityTypeConfiguration.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiResourceScopeEntityTypeConfiguration.cs new file mode 100644 index 000000000..0bb2487fc --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiResourceScopeEntityTypeConfiguration.cs @@ -0,0 +1,12 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.EntityConfigurations; + +public class ApiResourceScopeEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(apiResourceScope => apiResourceScope.Id); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiResourceSecretEntityTypeConfiguration.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiResourceSecretEntityTypeConfiguration.cs new file mode 100644 index 000000000..a147bb209 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiResourceSecretEntityTypeConfiguration.cs @@ -0,0 +1,14 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.EntityConfigurations; + +public class ApiResourceSecretEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.Property(x => x.Description).HasMaxLength(1000); + builder.Property(x => x.Value).HasMaxLength(4000).IsRequired(); + builder.Property(x => x.Type).HasMaxLength(250).IsRequired(); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiScopeClaimEntityTypeConfiguration.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiScopeClaimEntityTypeConfiguration.cs new file mode 100644 index 000000000..75f9f67a5 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiScopeClaimEntityTypeConfiguration.cs @@ -0,0 +1,12 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.EntityConfigurations; + +public class ApiScopeClaimEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(apiScopeClaim => apiScopeClaim.Id); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiScopeEntityTypeConfiguration.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiScopeEntityTypeConfiguration.cs new file mode 100644 index 000000000..e896c2544 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiScopeEntityTypeConfiguration.cs @@ -0,0 +1,18 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.EntityConfigurations; + +public class ApiScopeEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasIndex(apiScope => apiScope.Name).IsUnique(); + + builder.Property(apiScope => apiScope.Name).HasMaxLength(200).IsRequired(); + builder.Property(apiScope => apiScope.DisplayName).HasMaxLength(200); + builder.Property(apiScope => apiScope.Description).HasMaxLength(1000); + + builder.HasMany(apiScope => apiScope.UserClaims).WithOne(apiScope => apiScope.ApiScope).HasForeignKey(apiScope => apiScope.ApiScopeId).IsRequired().OnDelete(DeleteBehavior.Cascade); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiScopePropertyEntityTypeConfiguration.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiScopePropertyEntityTypeConfiguration.cs new file mode 100644 index 000000000..d1e77c39c --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ApiScopePropertyEntityTypeConfiguration.cs @@ -0,0 +1,13 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.EntityConfigurations; + +public class ApiScopePropertyEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.Property(x => x.Key).HasMaxLength(250).IsRequired(); + builder.Property(x => x.Value).HasMaxLength(2000).IsRequired(); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientClaimEntityTypeConfiguration.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientClaimEntityTypeConfiguration.cs new file mode 100644 index 000000000..f820fb239 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientClaimEntityTypeConfiguration.cs @@ -0,0 +1,13 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.EntityConfigurations; + +public class ClientClaimEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.Property(x => x.Type).HasMaxLength(250).IsRequired(); + builder.Property(x => x.Value).HasMaxLength(250).IsRequired(); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientCorsOriginEntityTypeConfiguration.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientCorsOriginEntityTypeConfiguration.cs new file mode 100644 index 000000000..b7d305fd0 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientCorsOriginEntityTypeConfiguration.cs @@ -0,0 +1,12 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.EntityConfigurations; + +public class ClientCorsOriginEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.Property(x => x.Origin).HasMaxLength(150).IsRequired(); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientEntityTypeConfiguration.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientEntityTypeConfiguration.cs new file mode 100644 index 000000000..6dfbec804 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientEntityTypeConfiguration.cs @@ -0,0 +1,35 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.EntityConfigurations; + +public class ClientEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.Property(x => x.ClientId).HasMaxLength(200).IsRequired(); + builder.Property(x => x.ProtocolType).HasMaxLength(200).IsRequired(); + builder.Property(x => x.ClientName).HasMaxLength(200); + builder.Property(x => x.ClientUri).HasMaxLength(2000); + builder.Property(x => x.LogoUri).HasMaxLength(2000); + builder.Property(x => x.Description).HasMaxLength(1000); + builder.Property(x => x.FrontChannelLogoutUri).HasMaxLength(2000); + builder.Property(x => x.BackChannelLogoutUri).HasMaxLength(2000); + builder.Property(x => x.ClientClaimsPrefix).HasMaxLength(200); + builder.Property(x => x.PairWiseSubjectSalt).HasMaxLength(200); + builder.Property(x => x.UserCodeType).HasMaxLength(100); + builder.Property(x => x.AllowedIdentityTokenSigningAlgorithms).HasMaxLength(100); + builder.HasIndex(x => x.ClientId); + builder.HasIndex(x => x.ClientId).IsUnique().HasFilter("[IsDeleted] = 0"); + + builder.HasMany(x => x.AllowedGrantTypes).WithOne(x => x.Client); + builder.HasMany(x => x.RedirectUris).WithOne(x => x.Client); + builder.HasMany(x => x.PostLogoutRedirectUris).WithOne(x => x.Client); + builder.HasMany(x => x.AllowedScopes).WithOne(x => x.Client); + builder.HasMany(x => x.ClientSecrets).WithOne(x => x.Client); + builder.HasMany(x => x.Claims).WithOne(x => x.Client); + builder.HasMany(x => x.IdentityProviderRestrictions).WithOne(x => x.Client); + builder.HasMany(x => x.AllowedCorsOrigins).WithOne(x => x.Client); + builder.HasMany(x => x.Properties).WithOne(x => x.Client); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientGrantTypeEntityTypeConfiguration.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientGrantTypeEntityTypeConfiguration.cs new file mode 100644 index 000000000..078f6bee9 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientGrantTypeEntityTypeConfiguration.cs @@ -0,0 +1,12 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.EntityConfigurations; + +public class ClientGrantTypeEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.Property(x => x.GrantType).HasMaxLength(250).IsRequired(); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientIdPRestrictionEntityTypeConfiguration.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientIdPRestrictionEntityTypeConfiguration.cs new file mode 100644 index 000000000..020d4b47a --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientIdPRestrictionEntityTypeConfiguration.cs @@ -0,0 +1,12 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.EntityConfigurations; + +public class ClientIdPRestrictionEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.Property(x => x.Provider).HasMaxLength(200).IsRequired(); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientPostLogoutRedirectUriEntityTypeConfiguration.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientPostLogoutRedirectUriEntityTypeConfiguration.cs new file mode 100644 index 000000000..9ec42b572 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientPostLogoutRedirectUriEntityTypeConfiguration.cs @@ -0,0 +1,12 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.EntityConfigurations; + +public class ClientPostLogoutRedirectUriEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(x => x.Id); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientPropertyEntityTypeConfiguration.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientPropertyEntityTypeConfiguration.cs new file mode 100644 index 000000000..2dfc932b7 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientPropertyEntityTypeConfiguration.cs @@ -0,0 +1,13 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.EntityConfigurations; + +public class ClientPropertyEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.Property(x => x.Key).HasMaxLength(250).IsRequired(); + builder.Property(x => x.Value).HasMaxLength(2000).IsRequired(); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientRedirectUriEntityTypeConfiguration.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientRedirectUriEntityTypeConfiguration.cs new file mode 100644 index 000000000..4bd36f03a --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientRedirectUriEntityTypeConfiguration.cs @@ -0,0 +1,12 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.EntityConfigurations; + +public class ClientRedirectUriEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.Property(x => x.RedirectUri).HasMaxLength(2000).IsRequired(); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientScopeEntityTypeConfiguration.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientScopeEntityTypeConfiguration.cs new file mode 100644 index 000000000..e1341c78f --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientScopeEntityTypeConfiguration.cs @@ -0,0 +1,12 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.EntityConfigurations; + +public class ClientScopeEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.Property(x => x.Scope).HasMaxLength(200).IsRequired(); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientSecretEntityTypeConfiguration.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientSecretEntityTypeConfiguration.cs new file mode 100644 index 000000000..63cff7b2a --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/ClientSecretEntityTypeConfiguration.cs @@ -0,0 +1,14 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.EntityConfigurations; + +public class ClientSecretEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.Property(x => x.Value).HasMaxLength(4000).IsRequired(); + builder.Property(x => x.Type).HasMaxLength(250).IsRequired(); + builder.Property(x => x.Description).HasMaxLength(2000); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/DeviceFlowCodesEntityTypeConfiguration.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/DeviceFlowCodesEntityTypeConfiguration.cs new file mode 100644 index 000000000..8d0acd9d9 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/DeviceFlowCodesEntityTypeConfiguration.cs @@ -0,0 +1,27 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.EntityConfigurations; + +public class DeviceFlowCodesEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.Property(x => x.DeviceCode).HasMaxLength(200).IsRequired(); + builder.Property(x => x.UserCode).HasMaxLength(200).IsRequired(); + builder.Property(x => x.SubjectId).HasMaxLength(200); + builder.Property(x => x.SessionId).HasMaxLength(100); + builder.Property(x => x.ClientId).HasMaxLength(200).IsRequired(); + builder.Property(x => x.Description).HasMaxLength(200); + builder.Property(x => x.CreationTime).IsRequired(); + builder.Property(x => x.Expiration).IsRequired(); + // 50000 chosen to be explicit to allow enough size to avoid truncation, yet stay beneath the MySql row size limit of ~65K + // apparently anything over 4K converts to nvarchar(max) on SqlServer + builder.Property(x => x.Data).HasMaxLength(50000).IsRequired(); + + builder.HasKey(x => new { x.UserCode }); + + builder.HasIndex(x => x.DeviceCode).IsUnique().HasFilter("[IsDeleted] = 0"); + builder.HasIndex(x => x.Expiration); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/IdentityResourceClaimEntityTypeConfiguration.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/IdentityResourceClaimEntityTypeConfiguration.cs new file mode 100644 index 000000000..1f96fd9bc --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/IdentityResourceClaimEntityTypeConfiguration.cs @@ -0,0 +1,12 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.EntityConfigurations; + +public class IdentityResourceClaimEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(identityResourceClaim => identityResourceClaim.Id); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/IdentityResourceEntityTypeConfiguration.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/IdentityResourceEntityTypeConfiguration.cs new file mode 100644 index 000000000..efe5181bc --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/IdentityResourceEntityTypeConfiguration.cs @@ -0,0 +1,18 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.EntityConfigurations; + +public class IdentityResourceEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.Property(x => x.Name).HasMaxLength(200).IsRequired(); + builder.Property(x => x.DisplayName).HasMaxLength(200); + builder.Property(x => x.Description).HasMaxLength(1000); + builder.HasIndex(x => x.Name).IsUnique().HasFilter("[IsDeleted] = 0"); + + builder.HasMany(x => x.UserClaims).WithOne(x => x.IdentityResource).HasForeignKey(x => x.IdentityResourceId).IsRequired().OnDelete(DeleteBehavior.Cascade); + builder.HasMany(x => x.Properties).WithOne(x => x.IdentityResource).HasForeignKey(x => x.IdentityResourceId).IsRequired().OnDelete(DeleteBehavior.Cascade); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/IdentityResourcePropertyEntityTypeConfiguration.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/IdentityResourcePropertyEntityTypeConfiguration.cs new file mode 100644 index 000000000..0ac7d865f --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/IdentityResourcePropertyEntityTypeConfiguration.cs @@ -0,0 +1,13 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.EntityConfigurations; + +public class IdentityResourcePropertyEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.Property(x => x.Key).HasMaxLength(250).IsRequired(); + builder.Property(x => x.Value).HasMaxLength(2000).IsRequired(); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/PersistedGrantEntityTypeConfiguration.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/PersistedGrantEntityTypeConfiguration.cs new file mode 100644 index 000000000..d01df6089 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/PersistedGrantEntityTypeConfiguration.cs @@ -0,0 +1,27 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.EntityConfigurations; + +public class PersistedGrantEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.Property(x => x.Key).HasMaxLength(200).ValueGeneratedNever(); + builder.Property(x => x.Type).HasMaxLength(50).IsRequired(); + builder.Property(x => x.SubjectId).HasMaxLength(200); + builder.Property(x => x.SessionId).HasMaxLength(100); + builder.Property(x => x.ClientId).HasMaxLength(200).IsRequired(); + builder.Property(x => x.Description).HasMaxLength(200); + builder.Property(x => x.CreationTime).IsRequired(); + // 50000 chosen to be explicit to allow enough size to avoid truncation, yet stay beneath the MySql row size limit of ~65K + // apparently anything over 4K converts to nvarchar(max) on SqlServer + builder.Property(x => x.Data).HasMaxLength(50000).IsRequired(); + + builder.HasKey(x => x.Key); + + builder.HasIndex(x => new { x.SubjectId, x.ClientId, x.Type }); + builder.HasIndex(x => new { x.SubjectId, x.SessionId, x.Type }); + builder.HasIndex(x => x.Expiration); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/UserClaimEntityTypeConfiguration.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/UserClaimEntityTypeConfiguration.cs new file mode 100644 index 000000000..1230b761d --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/EntityConfigurations/UserClaimEntityTypeConfiguration.cs @@ -0,0 +1,14 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.EntityConfigurations; + +public class UserClaimEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(x => x.Id); + builder.Property(x => x.Name).HasMaxLength(200).IsRequired(); + builder.Property(x => x.Description).HasMaxLength(1000); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.csproj b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.csproj new file mode 100644 index 000000000..e84f662aa --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Repositories/ApiResourceRepository.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Repositories/ApiResourceRepository.cs new file mode 100644 index 000000000..38868fa1e --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Repositories/ApiResourceRepository.cs @@ -0,0 +1,89 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.Repositories; + +public class ApiResourceRepository : IApiResourceRepository +{ + SyncCache _cache; + OidcDbContext _context; + + public ApiResourceRepository(SyncCache cache, OidcDbContext context) + { + _cache = cache; + _context = context; + } + + public async Task> GetPaginatedListAsync(int page, int pageSize, Expression>? condition = null) + { + condition ??= userClaim => true; + var query = _context.Set().Where(condition); + var total = await query.LongCountAsync(); + var apiResources = await query.OrderByDescending(s => s.ModificationTime) + .ThenByDescending(s => s.CreationTime) + .Skip((page - 1) * pageSize) + .Take(pageSize) + .ToListAsync(); + return new PaginatedList() + { + Total = total, + Result = apiResources + }; + } + + public async Task GetDetailAsync(int id) + { + var apiResource = await _context.Set() + .Include(apiResource => apiResource.UserClaims) + .ThenInclude(userClaim => userClaim.UserClaim) + .Include(apiResource => apiResource.Properties) + .Include(apiResource => apiResource.ApiScopes) + .ThenInclude(apiScope => apiScope.ApiScope) + .FirstOrDefaultAsync(apiResource => apiResource.Id == id); + + return apiResource; + } + + public async Task> GetListAsync() + { + var apiResources = await _context.Set().ToListAsync(); + return apiResources; + } + + public async Task FindAsync(Expression> predicate) + { + return await _context.Set().FirstOrDefaultAsync(predicate); + } + + public async Task GetCountAsync(Expression> predicate) + { + return await _context.Set().Where(predicate).CountAsync(); + } + + public async ValueTask AddAsync(ApiResource apiResource) + { + var exist = await _context.Set().CountAsync(a => a.Name == apiResource.Name) > 0; + if (exist) + throw new UserFriendlyException($"ApiResource with name {apiResource.Name} already exists"); + + var newApiResource = await _context.AddAsync(apiResource); + await _context.SaveChangesAsync(); + await _cache.SyncApiResourceCacheAsync(apiResource.Id); + return newApiResource.Entity; + } + + public async Task UpdateAsync(ApiResource apiResource) + { + var newApiResource = _context.Update(apiResource); + await _context.SaveChangesAsync(); + await _cache.SyncApiResourceCacheAsync(apiResource.Id); + return newApiResource.Entity; + } + + public async Task RemoveAsync(ApiResource apiResource) + { + _context.Remove(apiResource); + await _context.SaveChangesAsync(); + await _cache.RemoveApiResourceCacheAsync(apiResource); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Repositories/ApiScopeRepository.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Repositories/ApiScopeRepository.cs new file mode 100644 index 000000000..9f4d3039b --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Repositories/ApiScopeRepository.cs @@ -0,0 +1,87 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.Repositories; + +public class ApiScopeRepository : IApiScopeRepository +{ + SyncCache _cache; + OidcDbContext _context; + + public ApiScopeRepository(SyncCache cache, OidcDbContext context) + { + _cache = cache; + _context = context; + } + + public async Task> GetPaginatedListAsync(int page, int pageSize, Expression>? condition = null) + { + condition ??= userClaim => true; + var query = _context.Set().Where(condition); + var total = await query.LongCountAsync(); + var apiScopes = await query.OrderByDescending(s => s.ModificationTime) + .ThenByDescending(s => s.CreationTime) + .Skip((page - 1) * pageSize) + .Take(pageSize) + .ToListAsync(); + return new PaginatedList() + { + Total = total, + Result = apiScopes + }; + } + + public async Task GetDetailAsync(int id) + { + var apiScope = await _context.Set() + .Include(apiScope => apiScope.UserClaims) + .ThenInclude(apiScope => apiScope.UserClaim) + .Include(apiScope => apiScope.Properties) + .FirstOrDefaultAsync(apiScope => apiScope.Id == id); + + return apiScope; + } + + public async Task> GetListAsync() + { + var apiScopes = await _context.Set().ToListAsync(); + return apiScopes; + } + + public async Task FindAsync(Expression> predicate) + { + return await _context.Set().FirstOrDefaultAsync(predicate); + } + + public async Task GetCountAsync(Expression> predicate) + { + return await _context.Set().Where(predicate).CountAsync(); + } + + public async ValueTask AddAsync(ApiScope apiScope) + { + var exist = await _context.Set().CountAsync(a => a.Name == apiScope.Name) > 0; + if (exist) + throw new UserFriendlyException($"ApiScope with name {apiScope.Name} already exists"); + + var newApiScope = await _context.AddAsync(apiScope); + await _context.SaveChangesAsync(); + await _cache.SyncApiScopeCacheAsync(apiScope.Id); + return newApiScope.Entity; + } + + public async Task UpdateAsync(ApiScope apiScope) + { + var newApiScope = _context.Update(apiScope); + await _context.SaveChangesAsync(); + await _cache.SyncApiScopeCacheAsync(apiScope.Id); + return newApiScope.Entity; + } + + public async Task RemoveAsync(ApiScope apiScope) + { + _context.Remove(apiScope); + await _context.SaveChangesAsync(); + await _cache.RemoveApiScopeCacheAsync(apiScope); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Repositories/ClientRepository.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Repositories/ClientRepository.cs new file mode 100644 index 000000000..0e622d7d8 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Repositories/ClientRepository.cs @@ -0,0 +1,90 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.Repositories; + +public class ClientRepository : IClientRepository +{ + IClientCache _cache; + OidcDbContext _context; + + public ClientRepository(IClientCache cache, OidcDbContext context) + { + _cache = cache; + _context = context; + } + + public async Task> GetPaginatedListAsync(int page, int pageSize, Expression>? condition = null) + { + condition ??= userClaim => true; + var query = _context.Set().Where(condition); + var total = await query.LongCountAsync(); + var clients = await query.OrderByDescending(s => s.ModificationTime) + .ThenByDescending(s => s.CreationTime) + .Skip((page - 1) * pageSize) + .Take(pageSize) + .ToListAsync(); + return new PaginatedList() + { + Total = total, + Result = clients + }; + } + + public async Task GetDetailAsync(int id) + { + return await _context.Set() + .Where(c => c.Id == id) + .Include(c => c.AllowedGrantTypes) + .Include(c => c.RedirectUris) + .Include(c => c.PostLogoutRedirectUris) + .Include(c => c.Properties) + .Include(c => c.Claims) + .Include(c => c.IdentityProviderRestrictions) + .Include(c => c.AllowedCorsOrigins) + .Include(c => c.ClientSecrets) + .Include(c => c.AllowedScopes) + .FirstOrDefaultAsync(); + } + + public async Task> GetListAsync() + { + var clients = await _context.Set().ToListAsync(); + return clients; + } + + public async Task FindAsync(Expression> predicate) + { + return await _context.Set().FirstOrDefaultAsync(predicate); + } + + public async Task GetCountAsync(Expression> predicate) + { + return await _context.Set().Where(predicate).CountAsync(); + } + + public async ValueTask AddAsync(Client client) + { + var newClient = await _context.AddAsync(client); + await _context.SaveChangesAsync(); + var detail = await GetDetailAsync(client.Id); + await _cache.SetAsync(detail!); + return newClient.Entity; + } + + public async Task UpdateAsync(Client client) + { + var newClient = _context.Update(client); + await _context.SaveChangesAsync(); + var detail = await GetDetailAsync(client.Id); + await _cache.SetAsync(detail!); + return newClient.Entity; + } + + public async Task RemoveAsync(Client client) + { + _context.Remove(client); + await _context.SaveChangesAsync(); + await _cache.RemoveAsync(client); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Repositories/IdentityResourceRepository.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Repositories/IdentityResourceRepository.cs new file mode 100644 index 000000000..eba523d3d --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Repositories/IdentityResourceRepository.cs @@ -0,0 +1,112 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.Repositories; + +public class IdentityResourceRepository : IIdentityResourceRepository +{ + SyncCache _cache; + OidcDbContext _context; + + public IdentityResourceRepository(SyncCache cache, OidcDbContext context) + { + _cache = cache; + _context = context; + } + + public async Task> GetPaginatedListAsync(int page, int pageSize, Expression>? condition = null) + { + condition ??= userClaim => true; + var query = _context.Set().Where(condition); + var total = await query.LongCountAsync(); + var identityResources = await query.OrderByDescending(s => s.ModificationTime) + .ThenByDescending(s => s.CreationTime) + .Skip((page - 1) * pageSize) + .Take(pageSize) + .ToListAsync(); + return new PaginatedList() + { + Total = total, + Result = identityResources + }; + } + + public async Task> GetListAsync() + { + return await _context.Set().ToListAsync(); + } + + public async Task GetDetailAsync(int id) + { + var identityResources = await _context.Set() + .Include(idrs => idrs.UserClaims) + .Include(idrs => idrs.Properties) + .FirstOrDefaultAsync(idrs => idrs.Id == id); + + return identityResources; + } + + public async Task FindAsync(Expression> predicate) + { + return await _context.Set().FirstOrDefaultAsync(predicate); + } + + public async Task GetCountAsync(Expression> predicate) + { + return await _context.Set().Where(predicate).CountAsync(); + } + + public async ValueTask AddAsync(IdentityResource identityResource) + { + var exist = await _context.Set().CountAsync(idrs => idrs.Name == identityResource.Name) > 0; + if (exist) + throw new UserFriendlyException($"IdentityResource with name {identityResource.Name} already exists"); + + var newIdentityResource = await _context.AddAsync(identityResource); + await _context.SaveChangesAsync(); + await _cache.SyncIdentityResourceCacheAsync(identityResource.Id); + return newIdentityResource.Entity; + } + + public async Task UpdateAsync(IdentityResource identityResource) + { + var newIdentityResource = _context.Update(identityResource); + await _context.SaveChangesAsync(); + await _cache.SyncIdentityResourceCacheAsync(identityResource.Id); + + return newIdentityResource.Entity; + } + + public async Task RemoveAsync(IdentityResource identityResource) + { + _context.Remove(identityResource); + await _context.SaveChangesAsync(); + await _cache.RemoveIdentityResourceCacheAsync(identityResource); + } + + public async Task AddStandardIdentityResourcesAsync() + { + var userClaims = await _context.Set().ToListAsync(); + var syncIdentityResources = new List(); + foreach (var identityResource in StandardIdentityResources.IdentityResources) + { + var userClaimIds = userClaims.Where(uc => identityResource.UserClaims.Contains(uc.Name)).Select(uc => uc.Id); + var existData = await FindAsync(idrs => idrs.Name == identityResource.Name); + if (existData is not null) + { + existData.Update(identityResource.DisplayName, identityResource.Description ?? "", true, identityResource.Required, identityResource.Emphasize, identityResource.ShowInDiscoveryDocument, true); + existData.BindUserClaims(userClaimIds); + _context.Update(existData); + } + else + { + existData = new IdentityResource(identityResource.Name, identityResource.DisplayName, identityResource.Description ?? "", true, identityResource.Required, identityResource.Enabled, identityResource.ShowInDiscoveryDocument, true); + existData.BindUserClaims(userClaimIds); + await _context.AddAsync(existData); + } + syncIdentityResources.Add(existData); + } + await _context.SaveChangesAsync(); + await _cache.SyncIdentityResourceCacheAsync(syncIdentityResources.Select(idrs => idrs.Id).ToArray()); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Repositories/UserClaimRepository.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Repositories/UserClaimRepository.cs new file mode 100644 index 000000000..545f0af8c --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/Repositories/UserClaimRepository.cs @@ -0,0 +1,92 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.Repositories; + +public class UserClaimRepository : IUserClaimRepository +{ + OidcDbContext _context; + + public UserClaimRepository(OidcDbContext context) + { + _context = context; + } + + public async Task> GetPaginatedListAsync(int page, int pageSize, Expression>? condition = null) + { + condition ??= userClaim => true; + var query = _context.Set().Where(condition); + var total = await query.LongCountAsync(); + var userClaims = await query.OrderByDescending(s => s.ModificationTime) + .ThenByDescending(s => s.CreationTime) + .Skip((page - 1) * pageSize) + .Take(pageSize) + .ToListAsync(); + return new PaginatedList() + { + Total = total, + Result = userClaims + }; + } + + public async Task GetDetailAsync(int id) + { + var userClaim = await _context.Set() + .FirstOrDefaultAsync(userClaim => userClaim.Id == id); + + return userClaim; + } + + public async Task> GetListAsync() + { + var userClaims = await _context.Set().ToListAsync(); + return userClaims; + } + + public async Task FindAsync(Expression> predicate) + { + return await _context.Set().FirstOrDefaultAsync(predicate); + } + + public async Task GetCountAsync(Expression> predicate) + { + return await _context.Set().Where(predicate).CountAsync(); + } + + public async ValueTask AddAsync(UserClaim userClaim) + { + var exist = await _context.Set().CountAsync(uc => uc.Name == userClaim.Name) > 0; + if (exist) + throw new UserFriendlyException($"UserClaim with name {userClaim.Name} already exists"); + + var newUserClaim = await _context.AddAsync(userClaim); + await _context.SaveChangesAsync(); + return newUserClaim.Entity; + } + + public async Task UpdateAsync(UserClaim userClaim) + { + var newUserClaim = _context.Update(userClaim); + await _context.SaveChangesAsync(); + return newUserClaim.Entity; + } + + public async Task RemoveAsync(UserClaim userClaim) + { + _context.Remove(userClaim); + await _context.SaveChangesAsync(); + } + + public async Task AddStandardUserClaimsAsync() + { + var userClaims = new List(); + foreach (var claim in StandardUserClaims.Claims) + { + var exist = await GetCountAsync(userClaim => userClaim.Name == claim.Key) > 0; + if (exist) continue; + + userClaims.Add(new UserClaim(claim.Key, claim.Value)); + } + await _context.AddRangeAsync(userClaims); + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/ServiceCollectionExtensions.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/ServiceCollectionExtensions.cs new file mode 100644 index 000000000..282ba1423 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/ServiceCollectionExtensions.cs @@ -0,0 +1,43 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Authentication.Oidc.EntityFrameworkCore; + +public static class ServiceCollectionExtensions +{ + public static IServiceCollection AddOidcDbContext(this IServiceCollection services, Action optionsAction) + { + services.AddDbContext(optionsAction); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + + return services; + } + + public static IServiceCollection SeedClientData(this IServiceCollection services, List clients) + { + var clientRepository = services.BuildServiceProvider().GetRequiredService(); + var apiScopeRepository = services.BuildServiceProvider().GetRequiredService(); + + var scopes = clients.SelectMany(c => c.AllowedScopes); + foreach (var scope in scopes) + { + if (apiScopeRepository.FindAsync(s => s.Name == scope.Scope).Result == null) + { + _ = apiScopeRepository.AddAsync(new ApiScope(scope.Scope)).Result; + } + } + foreach (var client in clients) + { + if (clientRepository.FindAsync(s => s.ClientId == client.ClientId).Result == null) + { + _ = clientRepository.AddAsync(client).Result; + } + } + return services; + } +} diff --git a/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/_Imports.cs b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/_Imports.cs new file mode 100644 index 000000000..4e5d8cf58 --- /dev/null +++ b/src/Authentication/Masa.Contrib.Authentication.Oidc.EntityFrameworkCore/_Imports.cs @@ -0,0 +1,15 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +global using Masa.BuildingBlocks.Ddd.Domain.Repositories; +global using Masa.BuildingBlocks.Authentication.Oidc.Cache.Caches; +global using Masa.BuildingBlocks.Authentication.Oidc.Domain.Entities; +global using Masa.BuildingBlocks.Authentication.Oidc.Domain.Repositories; +global using Masa.BuildingBlocks.Authentication.Oidc.Models.Constans; +global using Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.Caches; +global using Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.DbContexts; +global using Masa.Contrib.Authentication.Oidc.EntityFrameworkCore.Repositories; +global using Microsoft.EntityFrameworkCore; +global using Microsoft.EntityFrameworkCore.Metadata.Builders; +global using Microsoft.Extensions.DependencyInjection; +global using System.Linq.Expressions; diff --git a/src/BuildingBlocks/MASA.BuildingBlocks b/src/BuildingBlocks/MASA.BuildingBlocks index f53f6af8f..2690161d1 160000 --- a/src/BuildingBlocks/MASA.BuildingBlocks +++ b/src/BuildingBlocks/MASA.BuildingBlocks @@ -1 +1 @@ -Subproject commit f53f6af8ff6dd6832440b7a117bc1a09fe382b11 +Subproject commit 2690161d1497c66f1837fc0276d39733ebc95d85