From dcf6be488212aa8e4cae360fb5cd6ae37f773ae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 24 Feb 2018 18:24:37 +0300 Subject: [PATCH] Added Authorization interceptor for application services. --- .../Authorization/AuthorizationInterceptor.cs | 45 +++++++++++++++++++ .../IMethodInvocationAuthorizationService.cs | 9 ++++ .../MethodInvocationAuthorizationContext.cs | 14 ++++++ .../MethodInvocationAuthorizationService.cs | 42 +++++++++++++++++ .../Volo/Abp/Collections/ITypeList.cs | 6 +++ .../Volo/Abp/Collections/TypeList.cs | 10 +++++ src/Volo.Abp.Ddd/Volo.Abp.Ddd.csproj | 1 + src/Volo.Abp.Ddd/Volo/Abp/AbpDddModule.cs | 5 +++ .../AuthorizationInterceptorRegistrar.cs | 16 +++++++ .../ValidationInterceptorRegistrar.cs | 3 +- .../Abp/Uow/UnitOfWorkInterceptorRegistrar.cs | 3 +- 11 files changed, 150 insertions(+), 4 deletions(-) create mode 100644 src/Volo.Abp.Authorization/Volo/Abp/Authorization/AuthorizationInterceptor.cs create mode 100644 src/Volo.Abp.Authorization/Volo/Abp/Authorization/IMethodInvocationAuthorizationService.cs create mode 100644 src/Volo.Abp.Authorization/Volo/Abp/Authorization/MethodInvocationAuthorizationContext.cs create mode 100644 src/Volo.Abp.Authorization/Volo/Abp/Authorization/MethodInvocationAuthorizationService.cs create mode 100644 src/Volo.Abp.Ddd/Volo/Abp/Application/Services/AuthorizationInterceptorRegistrar.cs diff --git a/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AuthorizationInterceptor.cs b/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AuthorizationInterceptor.cs new file mode 100644 index 0000000000..e7e99b777d --- /dev/null +++ b/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AuthorizationInterceptor.cs @@ -0,0 +1,45 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Volo.Abp.Aspects; +using Volo.Abp.DependencyInjection; +using Volo.Abp.DynamicProxy; +using Volo.Abp.Threading; + +namespace Volo.Abp.Authorization +{ + public class AuthorizationInterceptor : AbpInterceptor, ITransientDependency + { + private readonly IMethodInvocationAuthorizationService _methodInvocationAuthorizationService; + + public AuthorizationInterceptor(IMethodInvocationAuthorizationService methodInvocationAuthorizationService) + { + _methodInvocationAuthorizationService = methodInvocationAuthorizationService; + } + + public override void Intercept(IAbpMethodInvocation invocation) + { + AsyncHelper.RunSync(() => InterceptAsync(invocation)); + } + + public override async Task InterceptAsync(IAbpMethodInvocation invocation) + { + if (AbpCrossCuttingConcerns.IsApplied(invocation.TargetObject, AbpCrossCuttingConcerns.Authorization)) + { + await invocation.ProceedAsync(); + return; + } + + await AuthorizeAsync(invocation); + await invocation.ProceedAsync(); + } + + protected virtual Task AuthorizeAsync(IAbpMethodInvocation invocation) + { + return _methodInvocationAuthorizationService.CheckAsync( + new MethodInvocationAuthorizationContext( + invocation.Method + ) + ); + } + } +} diff --git a/src/Volo.Abp.Authorization/Volo/Abp/Authorization/IMethodInvocationAuthorizationService.cs b/src/Volo.Abp.Authorization/Volo/Abp/Authorization/IMethodInvocationAuthorizationService.cs new file mode 100644 index 0000000000..776bb592cb --- /dev/null +++ b/src/Volo.Abp.Authorization/Volo/Abp/Authorization/IMethodInvocationAuthorizationService.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.Authorization +{ + public interface IMethodInvocationAuthorizationService + { + Task CheckAsync(MethodInvocationAuthorizationContext context); + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Authorization/Volo/Abp/Authorization/MethodInvocationAuthorizationContext.cs b/src/Volo.Abp.Authorization/Volo/Abp/Authorization/MethodInvocationAuthorizationContext.cs new file mode 100644 index 0000000000..5b42d9b8b4 --- /dev/null +++ b/src/Volo.Abp.Authorization/Volo/Abp/Authorization/MethodInvocationAuthorizationContext.cs @@ -0,0 +1,14 @@ +using System.Reflection; + +namespace Volo.Abp.Authorization +{ + public class MethodInvocationAuthorizationContext + { + public MethodInfo Method { get; } + + public MethodInvocationAuthorizationContext(MethodInfo method) + { + Method = method; + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Authorization/Volo/Abp/Authorization/MethodInvocationAuthorizationService.cs b/src/Volo.Abp.Authorization/Volo/Abp/Authorization/MethodInvocationAuthorizationService.cs new file mode 100644 index 0000000000..de489c86a3 --- /dev/null +++ b/src/Volo.Abp.Authorization/Volo/Abp/Authorization/MethodInvocationAuthorizationService.cs @@ -0,0 +1,42 @@ +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Authorization +{ + public class MethodInvocationAuthorizationService : IMethodInvocationAuthorizationService, ITransientDependency + { + private readonly IAuthorizationService _authorizationService; + + public MethodInvocationAuthorizationService(IAuthorizationService authorizationService) + { + _authorizationService = authorizationService; + } + + public async Task CheckAsync(MethodInvocationAuthorizationContext context) + { + //TODO: Fully implement! (allow anonymous... etc.) + + var authorizationAttributes = GetAuthorizationDataAttributes(context); + foreach (var authorizationAttribute in authorizationAttributes) + { + await CheckAsync(authorizationAttribute); + } + } + + protected virtual IAuthorizeData[] GetAuthorizationDataAttributes(MethodInvocationAuthorizationContext context) + { + return context.Method + .GetCustomAttributes(true) + .OfType() + .ToArray(); + } + + protected async Task CheckAsync(IAuthorizeData authorizationAttribute) + { + await _authorizationService.CheckAsync(authorizationAttribute.Policy); + //TODO: What about roles and other props? + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Core/Volo/Abp/Collections/ITypeList.cs b/src/Volo.Abp.Core/Volo/Abp/Collections/ITypeList.cs index 76931accee..6d53ddc954 100644 --- a/src/Volo.Abp.Core/Volo/Abp/Collections/ITypeList.cs +++ b/src/Volo.Abp.Core/Volo/Abp/Collections/ITypeList.cs @@ -23,6 +23,12 @@ namespace Volo.Abp.Collections /// Type void Add() where T : TBaseType; + /// + /// Adds a type to list if it's not already in the list. + /// + /// Type + void TryAdd() where T : TBaseType; + /// /// Checks if a type exists in the list. /// diff --git a/src/Volo.Abp.Core/Volo/Abp/Collections/TypeList.cs b/src/Volo.Abp.Core/Volo/Abp/Collections/TypeList.cs index e96d40f213..24e66085f7 100644 --- a/src/Volo.Abp.Core/Volo/Abp/Collections/TypeList.cs +++ b/src/Volo.Abp.Core/Volo/Abp/Collections/TypeList.cs @@ -60,6 +60,16 @@ namespace Volo.Abp.Collections _typeList.Add(typeof(T)); } + public void TryAdd() where T : TBaseType + { + if (Contains()) + { + return; + } + + Add(); + } + /// public void Add(Type item) { diff --git a/src/Volo.Abp.Ddd/Volo.Abp.Ddd.csproj b/src/Volo.Abp.Ddd/Volo.Abp.Ddd.csproj index 36b734da8d..f79f78898f 100644 --- a/src/Volo.Abp.Ddd/Volo.Abp.Ddd.csproj +++ b/src/Volo.Abp.Ddd/Volo.Abp.Ddd.csproj @@ -14,6 +14,7 @@ + diff --git a/src/Volo.Abp.Ddd/Volo/Abp/AbpDddModule.cs b/src/Volo.Abp.Ddd/Volo/Abp/AbpDddModule.cs index ed316f6b16..61771a68a9 100644 --- a/src/Volo.Abp.Ddd/Volo/Abp/AbpDddModule.cs +++ b/src/Volo.Abp.Ddd/Volo/Abp/AbpDddModule.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Application.Services; +using Volo.Abp.Authorization; using Volo.Abp.Data; using Volo.Abp.EventBus; using Volo.Abp.Guids; @@ -15,6 +16,8 @@ using Volo.Abp.Validation; namespace Volo.Abp { + //TODO: Consider to split this DDD package by layers! + [DependsOn(typeof(AbpGuidsModule))] [DependsOn(typeof(AbpDataModule))] [DependsOn(typeof(AbpObjectMappingModule))] @@ -22,6 +25,7 @@ namespace Volo.Abp [DependsOn(typeof(AbpThreadingModule))] [DependsOn(typeof(AbpEventBusModule))] [DependsOn(typeof(AbpValidationModule))] + [DependsOn(typeof(AbpAuthorizationModule))] [DependsOn(typeof(AbpHttpAbstractionsModule))] public class AbpDddModule : AbpModule { @@ -29,6 +33,7 @@ namespace Volo.Abp { services.OnRegistred(UnitOfWorkInterceptorRegistrar.RegisterIfNeeded); services.OnRegistred(ValidationInterceptorRegistrar.RegisterIfNeeded); + services.OnRegistred(AuthorizationInterceptorRegistrar.RegisterIfNeeded); } public override void ConfigureServices(IServiceCollection services) diff --git a/src/Volo.Abp.Ddd/Volo/Abp/Application/Services/AuthorizationInterceptorRegistrar.cs b/src/Volo.Abp.Ddd/Volo/Abp/Application/Services/AuthorizationInterceptorRegistrar.cs new file mode 100644 index 0000000000..3e9f244e94 --- /dev/null +++ b/src/Volo.Abp.Ddd/Volo/Abp/Application/Services/AuthorizationInterceptorRegistrar.cs @@ -0,0 +1,16 @@ +using Volo.Abp.Authorization; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Application.Services +{ + public static class AuthorizationInterceptorRegistrar + { + public static void RegisterIfNeeded(IOnServiceRegistredContext context) + { + if (typeof(IApplicationService).IsAssignableFrom(context.ImplementationType)) + { + context.Interceptors.TryAdd(); + } + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Ddd/Volo/Abp/Application/Services/ValidationInterceptorRegistrar.cs b/src/Volo.Abp.Ddd/Volo/Abp/Application/Services/ValidationInterceptorRegistrar.cs index ea5f62b62f..d7e86de27a 100644 --- a/src/Volo.Abp.Ddd/Volo/Abp/Application/Services/ValidationInterceptorRegistrar.cs +++ b/src/Volo.Abp.Ddd/Volo/Abp/Application/Services/ValidationInterceptorRegistrar.cs @@ -9,8 +9,7 @@ namespace Volo.Abp.Application.Services { if (typeof(IApplicationService).IsAssignableFrom(context.ImplementationType)) { - //TODO: Notice that it may add the interceptor more than one for every exposed service type!? - context.Interceptors.Add(); + context.Interceptors.TryAdd(); } } } diff --git a/src/Volo.Abp.Ddd/Volo/Abp/Uow/UnitOfWorkInterceptorRegistrar.cs b/src/Volo.Abp.Ddd/Volo/Abp/Uow/UnitOfWorkInterceptorRegistrar.cs index 08f29812ce..849ca8ffd8 100644 --- a/src/Volo.Abp.Ddd/Volo/Abp/Uow/UnitOfWorkInterceptorRegistrar.cs +++ b/src/Volo.Abp.Ddd/Volo/Abp/Uow/UnitOfWorkInterceptorRegistrar.cs @@ -9,8 +9,7 @@ namespace Volo.Abp.Uow { if (UnitOfWorkHelper.IsUnitOfWorkType(context.ImplementationType.GetTypeInfo())) { - //TODO: Notice that it may add the interceptor more than one for every exposed service type!? - context.Interceptors.Add(); + context.Interceptors.TryAdd(); } } }