mirror of https://github.com/abpframework/abp.git
15 changed files with 173 additions and 21 deletions
@ -0,0 +1,57 @@ |
|||||
|
using IdentityServer4.Services; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Extensions.Logging.Abstractions; |
||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Caching; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.IdentityServer.Clients; |
||||
|
|
||||
|
namespace Volo.Abp.IdentityServer |
||||
|
{ |
||||
|
public class AbpCorsPolicyService : ICorsPolicyService |
||||
|
{ |
||||
|
public ILogger<AbpCorsPolicyService> Logger { get; set; } |
||||
|
protected IHybridServiceScopeFactory HybridServiceScopeFactory { get; } |
||||
|
protected IDistributedCache<AllowedCorsOriginsCacheItem> Cache { get; } |
||||
|
|
||||
|
public AbpCorsPolicyService( |
||||
|
IDistributedCache<AllowedCorsOriginsCacheItem> cache, |
||||
|
IHybridServiceScopeFactory hybridServiceScopeFactory) |
||||
|
{ |
||||
|
Cache = cache; |
||||
|
HybridServiceScopeFactory = hybridServiceScopeFactory; |
||||
|
Logger = NullLogger<AbpCorsPolicyService>.Instance; |
||||
|
} |
||||
|
|
||||
|
public async Task<bool> IsOriginAllowedAsync(string origin) |
||||
|
{ |
||||
|
var cacheItem = await Cache.GetOrAddAsync(AllowedCorsOriginsCacheItem.AllOrigins, CreateCacheItemAsync); |
||||
|
|
||||
|
var isAllowed = cacheItem.AllowedOrigins.Contains(origin, StringComparer.OrdinalIgnoreCase); |
||||
|
|
||||
|
if (!isAllowed) |
||||
|
{ |
||||
|
Logger.LogWarning($"Origin is not allowed: {origin}"); |
||||
|
} |
||||
|
|
||||
|
return isAllowed; |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<AllowedCorsOriginsCacheItem> CreateCacheItemAsync() |
||||
|
{ |
||||
|
// doing this here and not in the ctor because: https://github.com/aspnet/AspNetCore/issues/2377
|
||||
|
using (var scope = HybridServiceScopeFactory.CreateScope()) |
||||
|
{ |
||||
|
var clientRepository = scope.ServiceProvider.GetRequiredService<IClientRepository>(); |
||||
|
|
||||
|
return new AllowedCorsOriginsCacheItem |
||||
|
{ |
||||
|
AllowedOrigins = (await clientRepository.GetAllDistinctAllowedCorsOriginsAsync()).ToArray() |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
namespace Volo.Abp.IdentityServer |
||||
|
{ |
||||
|
public class AllowedCorsOriginsCacheItem |
||||
|
{ |
||||
|
public const string AllOrigins = "AllOrigins"; |
||||
|
|
||||
|
public string[] AllowedOrigins { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Caching; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Domain.Entities.Events; |
||||
|
using Volo.Abp.EventBus; |
||||
|
using Volo.Abp.IdentityServer.Clients; |
||||
|
|
||||
|
namespace Volo.Abp.IdentityServer |
||||
|
{ |
||||
|
public class AllowedCorsOriginsCacheItemInvalidator : ILocalEventHandler<EntityChangedEventData<Client>>, ITransientDependency |
||||
|
{ |
||||
|
protected IDistributedCache<AllowedCorsOriginsCacheItem> Cache { get; } |
||||
|
|
||||
|
public AllowedCorsOriginsCacheItemInvalidator(IDistributedCache<AllowedCorsOriginsCacheItem> cache) |
||||
|
{ |
||||
|
Cache = cache; |
||||
|
} |
||||
|
|
||||
|
public async Task HandleEventAsync(EntityChangedEventData<Client> eventData) |
||||
|
{ |
||||
|
await Cache.RemoveAsync(AllowedCorsOriginsCacheItem.AllOrigins); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
namespace Volo.Abp.IdentityServer |
||||
|
{ |
||||
|
public class AbpIdentityServerDomainTestBase : AbpIntegratedTest<AbpIdentityServerDomainTestModule> |
||||
|
{ |
||||
|
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
||||
|
{ |
||||
|
options.UseAutofac(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,41 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using IdentityServer4.Services; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.IdentityServer.Clients; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.IdentityServer |
||||
|
{ |
||||
|
public class CorsPolicyService_Tests : AbpIdentityServerDomainTestBase |
||||
|
{ |
||||
|
private readonly ICorsPolicyService _corsPolicyService; |
||||
|
private readonly IClientRepository _clientRepository; |
||||
|
|
||||
|
public CorsPolicyService_Tests() |
||||
|
{ |
||||
|
_corsPolicyService = GetRequiredService<ICorsPolicyService>(); |
||||
|
_clientRepository = GetRequiredService<IClientRepository>(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task IsOriginAllowedAsync() |
||||
|
{ |
||||
|
(await _corsPolicyService.IsOriginAllowedAsync("https://client1-origin.com")).ShouldBeTrue(); |
||||
|
(await _corsPolicyService.IsOriginAllowedAsync("https://unknown-origin.com")).ShouldBeFalse(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task IsOriginAllowedAsync_Should_Invalidate_Cache_On_Update() |
||||
|
{ |
||||
|
//It does not exists before
|
||||
|
(await _corsPolicyService.IsOriginAllowedAsync("https://new-origin.com")).ShouldBeFalse(); |
||||
|
|
||||
|
var client1 = await _clientRepository.FindByCliendIdAsync("ClientId1"); |
||||
|
client1.AddCorsOrigin("https://new-origin.com"); |
||||
|
await _clientRepository.UpdateAsync(client1); |
||||
|
|
||||
|
//It does exists now
|
||||
|
(await _corsPolicyService.IsOriginAllowedAsync("https://new-origin.com")).ShouldBeTrue(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue