Implemented AbpFeatureActionFilter.

pull/859/head
Halil ibrahim Kalkan 6 years ago
parent 1845479b24
commit 0c1eab7f9a

@ -3,6 +3,7 @@ using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Mvc.Auditing; using Volo.Abp.AspNetCore.Mvc.Auditing;
using Volo.Abp.AspNetCore.Mvc.Conventions; using Volo.Abp.AspNetCore.Mvc.Conventions;
using Volo.Abp.AspNetCore.Mvc.ExceptionHandling; using Volo.Abp.AspNetCore.Mvc.ExceptionHandling;
using Volo.Abp.AspNetCore.Mvc.Features;
using Volo.Abp.AspNetCore.Mvc.Uow; using Volo.Abp.AspNetCore.Mvc.Uow;
using Volo.Abp.AspNetCore.Mvc.Validation; using Volo.Abp.AspNetCore.Mvc.Validation;
@ -26,6 +27,7 @@ namespace Volo.Abp.AspNetCore.Mvc
private static void AddFilters(MvcOptions options) private static void AddFilters(MvcOptions options)
{ {
options.Filters.AddService(typeof(AbpAuditActionFilter)); options.Filters.AddService(typeof(AbpAuditActionFilter));
options.Filters.AddService(typeof(AbpFeatureActionFilter));
options.Filters.AddService(typeof(AbpValidationActionFilter)); options.Filters.AddService(typeof(AbpValidationActionFilter));
options.Filters.AddService(typeof(AbpUowActionFilter)); options.Filters.AddService(typeof(AbpUowActionFilter));
options.Filters.AddService(typeof(AbpExceptionFilter)); options.Filters.AddService(typeof(AbpExceptionFilter));

@ -0,0 +1,42 @@
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Volo.Abp.Aspects;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Features;
namespace Volo.Abp.AspNetCore.Mvc.Features
{
public class AbpFeatureActionFilter : IAsyncActionFilter, ITransientDependency
{
private readonly IMethodInvocationFeatureCheckerService _methodInvocationAuthorizationService;
public AbpFeatureActionFilter(IMethodInvocationFeatureCheckerService methodInvocationAuthorizationService)
{
_methodInvocationAuthorizationService = methodInvocationAuthorizationService;
}
public async Task OnActionExecutionAsync(
ActionExecutingContext context,
ActionExecutionDelegate next)
{
if (!context.ActionDescriptor.IsControllerAction())
{
await next();
return;
}
var methodInfo = context.ActionDescriptor.GetMethodInfo();
using (AbpCrossCuttingConcerns.Applying(context.Controller, AbpCrossCuttingConcerns.FeatureChecking))
{
await _methodInvocationAuthorizationService.CheckAsync(
new MethodInvocationFeatureCheckerContext(methodInfo)
);
await next();
}
}
}
}

@ -12,7 +12,6 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow
{ {
public class AbpUowActionFilter : IAsyncActionFilter, ITransientDependency public class AbpUowActionFilter : IAsyncActionFilter, ITransientDependency
{ {
private readonly IUnitOfWorkManager _unitOfWorkManager; private readonly IUnitOfWorkManager _unitOfWorkManager;
private readonly UnitOfWorkDefaultOptions _defaultOptions; private readonly UnitOfWorkDefaultOptions _defaultOptions;

@ -4,11 +4,10 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Features namespace Volo.Abp.Features
{ {
public class FeatureChecker : IFeatureChecker, ITransientDependency public class FeatureChecker : FeatureCheckerBase
{ {
protected FeatureOptions Options { get; } protected FeatureOptions Options { get; }
protected IServiceProvider ServiceProvider { get; } protected IServiceProvider ServiceProvider { get; }
@ -36,7 +35,7 @@ namespace Volo.Abp.Features
); );
} }
public virtual async Task<string> GetOrNullAsync(string name) public override async Task<string> GetOrNullAsync(string name)
{ {
var featureDefinition = FeatureDefinitionManager.Get(name); var featureDefinition = FeatureDefinitionManager.Get(name);
var providers = Enumerable var providers = Enumerable
@ -50,27 +49,6 @@ namespace Volo.Abp.Features
return await GetOrNullValueFromProvidersAsync(providers, featureDefinition); return await GetOrNullValueFromProvidersAsync(providers, featureDefinition);
} }
public async Task<bool> IsEnabledAsync(string name)
{
var value = await GetOrNullAsync(name);
if (value == null)
{
return false;
}
try
{
return bool.Parse(value);
}
catch (Exception ex)
{
throw new AbpException(
$"The value '{value}' for the feature '{name}' should be a boolean, but was not!",
ex
);
}
}
protected virtual async Task<string> GetOrNullValueFromProvidersAsync( protected virtual async Task<string> GetOrNullValueFromProvidersAsync(
IEnumerable<IFeatureValueProvider> providers, IEnumerable<IFeatureValueProvider> providers,
FeatureDefinition feature) FeatureDefinition feature)

@ -0,0 +1,32 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Features
{
public abstract class FeatureCheckerBase : IFeatureChecker, ITransientDependency
{
public abstract Task<string> GetOrNullAsync(string name);
public virtual async Task<bool> IsEnabledAsync(string name)
{
var value = await GetOrNullAsync(name);
if (value == null)
{
return false;
}
try
{
return bool.Parse(value);
}
catch (Exception ex)
{
throw new AbpException(
$"The value '{value}' for the feature '{name}' should be a boolean, but was not!",
ex
);
}
}
}
}

@ -6,7 +6,6 @@ using Volo.Abp.AspNetCore.Mvc.Authorization;
using Volo.Abp.AspNetCore.Mvc.Localization; using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.AspNetCore.Mvc.Localization.Resource; using Volo.Abp.AspNetCore.Mvc.Localization.Resource;
using Volo.Abp.AspNetCore.TestBase; using Volo.Abp.AspNetCore.TestBase;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Autofac; using Volo.Abp.Autofac;
using Volo.Abp.Localization; using Volo.Abp.Localization;
using Volo.Abp.Localization.Resources.AbpValidation; using Volo.Abp.Localization.Resources.AbpValidation;

@ -0,0 +1,27 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.Features;
namespace Volo.Abp.AspNetCore.Mvc.Features
{
public class FakeFeatureChecker : FeatureCheckerBase
{
public override Task<string> GetOrNullAsync(string name)
{
return Task.FromResult(GetOrNull(name));
}
private static string GetOrNull(string name)
{
switch (name)
{
case "AllowedFeature":
return true.ToString();
case "NotAllowedFeature":
return null; //or false, doesn't matter
}
throw new ApplicationException($"Unknown feature: '{name}'");
}
}
}

@ -0,0 +1,33 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.Features;
namespace Volo.Abp.AspNetCore.Mvc.Features
{
[Route("api/feature-test")]
public class FeatureTestController : AbpController
{
[HttpGet]
[Route("allowed-feature")]
[RequiresFeature("AllowedFeature")]
public Task AllowedFeatureAsync()
{
return Task.CompletedTask;
}
[HttpGet]
[Route("not-allowed-feature")]
[RequiresFeature("NotAllowedFeature")]
public void NotAllowedFeature()
{
}
[HttpGet]
[Route("no-feature")]
public int NoFeature()
{
return 42;
}
}
}

@ -0,0 +1,34 @@
using System.Net;
using System.Threading.Tasks;
using Xunit;
namespace Volo.Abp.AspNetCore.Mvc.Features
{
public class FeatureTestController_Tests : AspNetCoreMvcTestBase
{
[Fact]
public async Task Should_Allow_Enabled_Features()
{
await GetResponseAsStringAsync(
"/api/feature-test/allowed-feature"
);
}
[Fact]
public async Task Should_Not_Allow_Not_Enabled_Features()
{
await GetResponseAsStringAsync(
"/api/feature-test/not-allowed-feature",
HttpStatusCode.Unauthorized
);
}
[Fact]
public async Task Should_Allow_Actions_With_No_Feature()
{
await GetResponseAsStringAsync(
"/api/feature-test/no-feature"
);
}
}
}
Loading…
Cancel
Save