From 74001e550e5921fdf558b9eb57996c254ccf1064 Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 1 Sep 2021 12:24:30 +0800 Subject: [PATCH 1/6] Use ASP NET Core's AuthenticationScheme to handle AbpAuthorizationException. Resolve #9926 --- .../ExceptionHandling/AbpExceptionFilter.cs | 26 +++++-- .../AbpExceptionPageFilter.cs | 26 +++++-- ...AbpAuthorizationExceptionHandlerOptions.cs | 17 +++++ .../AbpExceptionHandlingMiddleware.cs | 24 +++++-- ...DefaultAbpAuthorizationExceptionHandler.cs | 68 ++++++++++++++++++ .../IAbpAuthorizationExceptionHandler.cs | 11 +++ .../Volo.Abp.AspNetCore.Mvc.Tests.csproj | 1 + .../Mvc/AbpAspNetCoreMvcTestModule.cs | 7 ++ .../Authorization/AuthTestController_Tests.cs | 6 +- ...horizationExceptionTestController_Tests.cs | 70 +++++++++++++++++++ ...AbpAuthorizationExceptionTestPage_Tests.cs | 70 +++++++++++++++++++ .../ExceptionTestController.cs | 8 +++ .../ExceptionTestController_Tests.cs | 43 +++++++++++- .../ExceptionTestPage.cshtml.cs | 5 ++ .../ExceptionTestPage_Tests.cs | 42 +++++++++++ .../FakeAuthenticationMiddleware.cs | 2 +- .../Mvc/{Authorization => }/FakeUserClaims.cs | 4 +- 17 files changed, 401 insertions(+), 29 deletions(-) create mode 100644 framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpAuthorizationExceptionHandlerOptions.cs create mode 100644 framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultAbpAuthorizationExceptionHandler.cs create mode 100644 framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/IAbpAuthorizationExceptionHandler.cs create mode 100644 framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpAuthorizationExceptionTestController_Tests.cs create mode 100644 framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpAuthorizationExceptionTestPage_Tests.cs rename framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/{Authorization => }/FakeAuthenticationMiddleware.cs (94%) rename framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/{Authorization => }/FakeUserClaims.cs (82%) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs index 6c447bc893..b1ce1dda92 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs @@ -5,10 +5,12 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.ExceptionHandling; +using Volo.Abp.Authorization; using Volo.Abp.DependencyInjection; using Volo.Abp.ExceptionHandling; using Volo.Abp.Http; @@ -55,17 +57,10 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling { //TODO: Trigger an AbpExceptionHandled event or something like that. - context.HttpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true"); - context.HttpContext.Response.StatusCode = (int) context - .GetRequiredService() - .GetStatusCode(context.HttpContext, context.Exception); - var exceptionHandlingOptions = context.GetRequiredService>().Value; var exceptionToErrorInfoConverter = context.GetRequiredService(); var remoteServiceErrorInfo = exceptionToErrorInfoConverter.Convert(context.Exception, exceptionHandlingOptions.SendExceptionsDetailsToClients); - context.Result = new ObjectResult(new RemoteServiceErrorResponse(remoteServiceErrorInfo)); - var logLevel = context.Exception.GetLogLevel(); var remoteServiceErrorInfoBuilder = new StringBuilder(); @@ -80,6 +75,23 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling await context.GetRequiredService().NotifyAsync(new ExceptionNotificationContext(context.Exception)); + if (context.Exception is AbpAuthorizationException) + { + if (await context.HttpContext.RequestServices.GetRequiredService() + .HandleAsync(context.Exception.As(), context.HttpContext)) + { + context.Exception = null; //Handled! + return; + } + } + + context.HttpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true"); + context.HttpContext.Response.StatusCode = (int) context + .GetRequiredService() + .GetStatusCode(context.HttpContext, context.Exception); + + context.Result = new ObjectResult(new RemoteServiceErrorResponse(remoteServiceErrorInfo)); + context.Exception = null; //Handled! } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs index f3666d2f91..e6ebc235d1 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs @@ -5,10 +5,12 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.ExceptionHandling; +using Volo.Abp.Authorization; using Volo.Abp.DependencyInjection; using Volo.Abp.ExceptionHandling; using Volo.Abp.Http; @@ -67,17 +69,10 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling { //TODO: Trigger an AbpExceptionHandled event or something like that. - context.HttpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true"); - context.HttpContext.Response.StatusCode = (int) context - .GetRequiredService() - .GetStatusCode(context.HttpContext, context.Exception); - var exceptionHandlingOptions = context.GetRequiredService>().Value; var exceptionToErrorInfoConverter = context.GetRequiredService(); var remoteServiceErrorInfo = exceptionToErrorInfoConverter.Convert(context.Exception, exceptionHandlingOptions.SendExceptionsDetailsToClients); - context.Result = new ObjectResult(new RemoteServiceErrorResponse(remoteServiceErrorInfo)); - var logLevel = context.Exception.GetLogLevel(); var remoteServiceErrorInfoBuilder = new StringBuilder(); @@ -91,6 +86,23 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling await context.GetRequiredService().NotifyAsync(new ExceptionNotificationContext(context.Exception)); + if (context.Exception is AbpAuthorizationException) + { + if (await context.HttpContext.RequestServices.GetRequiredService() + .HandleAsync(context.Exception.As(), context.HttpContext)) + { + context.Exception = null; //Handled! + return; + } + } + + context.HttpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true"); + context.HttpContext.Response.StatusCode = (int) context + .GetRequiredService() + .GetStatusCode(context.HttpContext, context.Exception); + + context.Result = new ObjectResult(new RemoteServiceErrorResponse(remoteServiceErrorInfo)); + context.Exception = null; //Handled! } } diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpAuthorizationExceptionHandlerOptions.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpAuthorizationExceptionHandlerOptions.cs new file mode 100644 index 0000000000..8adc4383d0 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpAuthorizationExceptionHandlerOptions.cs @@ -0,0 +1,17 @@ +namespace Volo.Abp.AspNetCore.ExceptionHandling +{ + public class AbpAuthorizationExceptionHandlerOptions + { + public bool UseAuthenticationScheme { get; set; } + + /// + /// Use default forbid/challenge scheme if this is not specified. + /// + public string AuthenticationScheme { get; set; } + + public AbpAuthorizationExceptionHandlerOptions() + { + UseAuthenticationScheme = true; + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs index 9535aab149..b4aa9745b5 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.Net.Http.Headers; using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.Authorization; using Volo.Abp.DependencyInjection; using Volo.Abp.ExceptionHandling; using Volo.Abp.Http; @@ -58,6 +59,22 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling { _logger.LogException(exception); + await httpContext + .RequestServices + .GetRequiredService() + .NotifyAsync( + new ExceptionNotificationContext(exception) + ); + + if (exception is AbpAuthorizationException) + { + if (await httpContext.RequestServices.GetRequiredService() + .HandleAsync(exception.As(), httpContext)) + { + return; + } + } + var errorInfoConverter = httpContext.RequestServices.GetRequiredService(); var statusCodeFinder = httpContext.RequestServices.GetRequiredService(); var jsonSerializer = httpContext.RequestServices.GetRequiredService(); @@ -75,13 +92,6 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling ) ) ); - - await httpContext - .RequestServices - .GetRequiredService() - .NotifyAsync( - new ExceptionNotificationContext(exception) - ); } private Task ClearCacheHeaders(object state) diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultAbpAuthorizationExceptionHandler.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultAbpAuthorizationExceptionHandler.cs new file mode 100644 index 0000000000..8e86878294 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultAbpAuthorizationExceptionHandler.cs @@ -0,0 +1,68 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.Authorization; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.AspNetCore.ExceptionHandling +{ + public class DefaultAbpAuthorizationExceptionHandler : IAbpAuthorizationExceptionHandler, ITransientDependency + { + public virtual async Task HandleAsync(AbpAuthorizationException exception, HttpContext httpContext) + { + var isAuthenticated = httpContext.User.Identity?.IsAuthenticated ?? false; + + var handlerOptions = httpContext.RequestServices.GetRequiredService>().Value; + if (handlerOptions.UseAuthenticationScheme) + { + var handlers = httpContext.RequestServices.GetRequiredService(); + + if (!handlerOptions.AuthenticationScheme.IsNullOrWhiteSpace()) + { + var handler = await handlers.GetHandlerAsync(httpContext, handlerOptions.AuthenticationScheme); + if (handler != null) + { + if (isAuthenticated) + { + await handler.ForbidAsync(null); + } + else + { + await handler.ChallengeAsync(null); + } + + return true; + } + } + + var authenticationSchemeProvider = httpContext.RequestServices.GetRequiredService(); + var scheme = isAuthenticated + ? await authenticationSchemeProvider.GetDefaultForbidSchemeAsync() + : await authenticationSchemeProvider.GetDefaultChallengeSchemeAsync(); + + if (scheme != null) + { + var handler = await handlers.GetHandlerAsync(httpContext, scheme.Name); + if (handler != null) + { + if (isAuthenticated) + { + await handler.ForbidAsync(null); + } + else + { + await handler.ChallengeAsync(null); + } + + return true; + } + } + } + + return false; + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/IAbpAuthorizationExceptionHandler.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/IAbpAuthorizationExceptionHandler.cs new file mode 100644 index 0000000000..9f95c18f28 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/IAbpAuthorizationExceptionHandler.cs @@ -0,0 +1,11 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Volo.Abp.Authorization; + +namespace Volo.Abp.AspNetCore.ExceptionHandling +{ + public interface IAbpAuthorizationExceptionHandler + { + Task HandleAsync(AbpAuthorizationException exception, HttpContext httpContext); + } +} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo.Abp.AspNetCore.Mvc.Tests.csproj b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo.Abp.AspNetCore.Mvc.Tests.csproj index e07798d4b9..92079bef09 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo.Abp.AspNetCore.Mvc.Tests.csproj +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo.Abp.AspNetCore.Mvc.Tests.csproj @@ -21,6 +21,7 @@ + diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs index 3c186e3fea..fc84b9c496 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs @@ -53,6 +53,12 @@ namespace Volo.Abp.AspNetCore.Mvc .EnableAll(); }); + context.Services.AddAuthentication(options => + { + options.DefaultChallengeScheme = "Bearer"; + options.DefaultForbidScheme = "Cookie"; + }).AddCookie("Cookie").AddJwtBearer("Bearer", _ => { }); + context.Services.AddAuthorization(options => { options.AddPolicy("MyClaimTestPolicy", policy => @@ -116,6 +122,7 @@ namespace Volo.Abp.AspNetCore.Mvc app.UseRouting(); app.UseMiddleware(); app.UseAbpClaimsMap(); + app.UseAuthentication(); app.UseAuthorization(); app.UseAuditing(); app.UseUnitOfWork(); diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/AuthTestController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/AuthTestController_Tests.cs index 749f3cb12b..3129ccf55d 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/AuthTestController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/AuthTestController_Tests.cs @@ -1,4 +1,5 @@ using System; +using System.Net; using System.Security.Claims; using System.Threading.Tasks; using Shouldly; @@ -57,10 +58,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Authorization new Claim("MyCustomClaimType", "43") }); - //TODO: We can get a real exception if we properly configure authentication schemas for this project - await Assert.ThrowsAsync(async () => - await GetResponseAsStringAsync("/AuthTest/CustomPolicyTest") - ); + await GetResponseAsStringAsync("/AuthTest/CustomPolicyTest", HttpStatusCode.Redirect); } [Fact] diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpAuthorizationExceptionTestController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpAuthorizationExceptionTestController_Tests.cs new file mode 100644 index 0000000000..6dd4a97d7c --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpAuthorizationExceptionTestController_Tests.cs @@ -0,0 +1,70 @@ +using System; +using System.Net; +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using NSubstitute; +using Shouldly; +using Volo.Abp.AspNetCore.ExceptionHandling; +using Volo.Abp.ExceptionHandling; +using Volo.Abp.Security.Claims; +using Xunit; + +namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling +{ + public class AbpAuthorizationExceptionTestController_Tests : AspNetCoreMvcTestBase + { + protected IExceptionSubscriber FakeExceptionSubscriber; + + protected FakeUserClaims FakeRequiredService; + + public AbpAuthorizationExceptionTestController_Tests() + { + FakeRequiredService = GetRequiredService(); + } + + protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + { + base.ConfigureServices(context, services); + + FakeExceptionSubscriber = Substitute.For(); + + services.AddSingleton(FakeExceptionSubscriber); + + services.Configure(options => + { + options.UseAuthenticationScheme = true; + options.AuthenticationScheme = "Cookie"; + }); + } + + [Fact] + public virtual async Task Should_Handle_By_Cookie_AuthenticationScheme_For_AbpAuthorizationException() + { + var result = await GetResponseAsync("/api/exception-test/AbpAuthorizationException", HttpStatusCode.Redirect); + result.Headers.Location.ToString().ShouldContain("http://localhost/Account/Login"); + +#pragma warning disable 4014 + FakeExceptionSubscriber + .Received() + .HandleAsync(Arg.Any()); +#pragma warning restore 4014 + + + FakeRequiredService.Claims.AddRange(new[] + { + new Claim(AbpClaimTypes.UserId, Guid.NewGuid().ToString()) + }); + + result = await GetResponseAsync("/api/exception-test/AbpAuthorizationException", HttpStatusCode.Redirect); + result.Headers.Location.ToString().ShouldContain("http://localhost/Account/AccessDenied"); + +#pragma warning disable 4014 + FakeExceptionSubscriber + .Received() + .HandleAsync(Arg.Any()); +#pragma warning restore 4014 + } + } +} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpAuthorizationExceptionTestPage_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpAuthorizationExceptionTestPage_Tests.cs new file mode 100644 index 0000000000..f3bf1cca6d --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpAuthorizationExceptionTestPage_Tests.cs @@ -0,0 +1,70 @@ +using System; +using System.Net; +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using NSubstitute; +using Shouldly; +using Volo.Abp.AspNetCore.ExceptionHandling; +using Volo.Abp.ExceptionHandling; +using Volo.Abp.Security.Claims; +using Xunit; + +namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling +{ + public class AbpAuthorizationExceptionTestPage_Tests : AspNetCoreMvcTestBase + { + private IExceptionSubscriber _fakeExceptionSubscriber; + + private FakeUserClaims _fakeRequiredService; + + public AbpAuthorizationExceptionTestPage_Tests() + { + _fakeRequiredService = GetRequiredService(); + } + + protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + { + base.ConfigureServices(context, services); + + _fakeExceptionSubscriber = Substitute.For(); + + services.AddSingleton(_fakeExceptionSubscriber); + + services.Configure(options => + { + options.UseAuthenticationScheme = true; + options.AuthenticationScheme = "Cookie"; + }); + } + + [Fact] + public virtual async Task Should_Handle_By_Cookie_AuthenticationScheme_For_AbpAuthorizationException() + { + var result = await GetResponseAsync("/ExceptionHandling/ExceptionTestPage?handler=AbpAuthorizationException", HttpStatusCode.Redirect); + result.Headers.Location.ToString().ShouldContain("http://localhost/Account/Login"); + +#pragma warning disable 4014 + _fakeExceptionSubscriber + .Received() + .HandleAsync(Arg.Any()); +#pragma warning restore 4014 + + + _fakeRequiredService.Claims.AddRange(new[] + { + new Claim(AbpClaimTypes.UserId, Guid.NewGuid().ToString()) + }); + + result = await GetResponseAsync("/ExceptionHandling/ExceptionTestPage?handler=AbpAuthorizationException", HttpStatusCode.Redirect); + result.Headers.Location.ToString().ShouldContain("http://localhost/Account/AccessDenied"); + +#pragma warning disable 4014 + _fakeExceptionSubscriber + .Received() + .HandleAsync(Arg.Any()); +#pragma warning restore 4014 + } + } +} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestController.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestController.cs index 8ada2e03d0..0ca267c364 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestController.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestController.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Mvc; +using Volo.Abp.Authorization; namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling { @@ -18,5 +19,12 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling { throw new UserFriendlyException("This is a sample exception!"); } + + [HttpGet] + [Route("AbpAuthorizationException")] + public void AbpAuthorizationException() + { + throw new AbpAuthorizationException("This is a sample exception!"); + } } } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestController_Tests.cs index 46cdd073e7..131dbd905f 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestController_Tests.cs @@ -1,4 +1,6 @@ -using System.Net; +using System; +using System.Net; +using System.Security.Claims; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -6,6 +8,7 @@ using NSubstitute; using Shouldly; using Volo.Abp.ExceptionHandling; using Volo.Abp.Http; +using Volo.Abp.Security.Claims; using Xunit; namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling @@ -14,6 +17,13 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling { private IExceptionSubscriber _fakeExceptionSubscriber; + private FakeUserClaims FakeRequiredService; + + public ExceptionTestController_Tests() + { + FakeRequiredService = GetRequiredService(); + } + protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) { base.ConfigureServices(context, services); @@ -50,6 +60,37 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling _fakeExceptionSubscriber .DidNotReceive() .HandleAsync(Arg.Any()); +#pragma warning restore 4014 + } + + [Fact] + public virtual async Task Should_Handle_By_Cookie_AuthenticationScheme_For_AbpAuthorizationException_For_Void_Return_Value() + { + FakeRequiredService.Claims.AddRange(new[] + { + new Claim(AbpClaimTypes.UserId, Guid.NewGuid().ToString()) + }); + + var result = await GetResponseAsync("/api/exception-test/AbpAuthorizationException", HttpStatusCode.Redirect); + result.Headers.Location.ToString().ShouldContain("http://localhost/Account/AccessDenied"); + +#pragma warning disable 4014 + _fakeExceptionSubscriber + .Received() + .HandleAsync(Arg.Any()); +#pragma warning restore 4014 + } + + [Fact] + public virtual async Task Should_Handle_By_JwtBearer_AuthenticationScheme_For_AbpAuthorizationException_For_Void_Return_Value() + { + var result = await GetResponseAsync("/api/exception-test/AbpAuthorizationException", HttpStatusCode.Unauthorized); + result.Headers.WwwAuthenticate.ToString().ShouldBe("Bearer"); + +#pragma warning disable 4014 + _fakeExceptionSubscriber + .Received() + .HandleAsync(Arg.Any()); #pragma warning restore 4014 } } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestPage.cshtml.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestPage.cshtml.cs index dd4edebec1..ba040b7051 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestPage.cshtml.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestPage.cshtml.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; +using Volo.Abp.Authorization; namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling { @@ -31,5 +32,9 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling throw new UserFriendlyException("This is a sample exception!"); } + public Task OnGetAbpAuthorizationException() + { + throw new AbpAuthorizationException("This is a sample exception!"); + } } } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestPage_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestPage_Tests.cs index d7c609aa59..df87e31ae3 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestPage_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestPage_Tests.cs @@ -1,4 +1,6 @@ +using System; using System.Net; +using System.Security.Claims; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -6,6 +8,7 @@ using NSubstitute; using Shouldly; using Volo.Abp.ExceptionHandling; using Volo.Abp.Http; +using Volo.Abp.Security.Claims; using Xunit; namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling @@ -14,6 +17,13 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling { private IExceptionSubscriber _fakeExceptionSubscriber; + private FakeUserClaims _fakeRequiredService; + + public ExceptionTestPage_Tests() + { + _fakeRequiredService = GetRequiredService(); + } + protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) { base.ConfigureServices(context, services); @@ -92,6 +102,38 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling result.Error.ShouldNotBeNull(); result.Error.Message.ShouldBe("This is a sample exception!"); +#pragma warning disable 4014 + _fakeExceptionSubscriber + .Received() + .HandleAsync(Arg.Any()); +#pragma warning restore 4014 + } + + + [Fact] + public virtual async Task Should_Handle_By_Cookie_AuthenticationScheme_For_AbpAuthorizationException_For_Void_Return_Value() + { + _fakeRequiredService.Claims.AddRange(new[] + { + new Claim(AbpClaimTypes.UserId, Guid.NewGuid().ToString()) + }); + + var result = await GetResponseAsync("/ExceptionHandling/ExceptionTestPage?handler=AbpAuthorizationException", HttpStatusCode.Redirect); + result.Headers.Location.ToString().ShouldContain("http://localhost/Account/AccessDenied"); + +#pragma warning disable 4014 + _fakeExceptionSubscriber + .Received() + .HandleAsync(Arg.Any()); +#pragma warning restore 4014 + } + + [Fact] + public virtual async Task Should_Handle_By_JwtBearer_AuthenticationScheme_For_AbpAuthorizationException_For_Void_Return_Value() + { + var result = await GetResponseAsync("/ExceptionHandling/ExceptionTestPage?handler=AbpAuthorizationException", HttpStatusCode.Unauthorized); + result.Headers.WwwAuthenticate.ToString().ShouldBe("Bearer"); + #pragma warning disable 4014 _fakeExceptionSubscriber .Received() diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/FakeAuthenticationMiddleware.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/FakeAuthenticationMiddleware.cs similarity index 94% rename from framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/FakeAuthenticationMiddleware.cs rename to framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/FakeAuthenticationMiddleware.cs index 5ee6ec5c1f..4aed555bca 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/FakeAuthenticationMiddleware.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/FakeAuthenticationMiddleware.cs @@ -5,7 +5,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Volo.Abp.DependencyInjection; -namespace Volo.Abp.AspNetCore.Mvc.Authorization +namespace Volo.Abp.AspNetCore.Mvc { public class FakeAuthenticationMiddleware : IMiddleware, ITransientDependency { diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/FakeUserClaims.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/FakeUserClaims.cs similarity index 82% rename from framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/FakeUserClaims.cs rename to framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/FakeUserClaims.cs index 2c78ee6fb6..d4ecb47fc1 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/FakeUserClaims.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/FakeUserClaims.cs @@ -2,10 +2,10 @@ using System.Security.Claims; using Volo.Abp.DependencyInjection; -namespace Volo.Abp.AspNetCore.Mvc.Authorization +namespace Volo.Abp.AspNetCore.Mvc { public class FakeUserClaims : ISingletonDependency { public List Claims { get; } = new List(); } -} \ No newline at end of file +} From 380971264d6eb378b1bb45275d583d045e33f2d1 Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 1 Sep 2021 14:11:18 +0800 Subject: [PATCH 2/6] Refactor DefaultAbpAuthorizationExceptionHandler. --- ...DefaultAbpAuthorizationExceptionHandler.cs | 29 ++++--------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultAbpAuthorizationExceptionHandler.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultAbpAuthorizationExceptionHandler.cs index 8e86878294..de2a059715 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultAbpAuthorizationExceptionHandler.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultAbpAuthorizationExceptionHandler.cs @@ -18,33 +18,16 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling var handlerOptions = httpContext.RequestServices.GetRequiredService>().Value; if (handlerOptions.UseAuthenticationScheme) { - var handlers = httpContext.RequestServices.GetRequiredService(); - - if (!handlerOptions.AuthenticationScheme.IsNullOrWhiteSpace()) - { - var handler = await handlers.GetHandlerAsync(httpContext, handlerOptions.AuthenticationScheme); - if (handler != null) - { - if (isAuthenticated) - { - await handler.ForbidAsync(null); - } - else - { - await handler.ChallengeAsync(null); - } - - return true; - } - } - var authenticationSchemeProvider = httpContext.RequestServices.GetRequiredService(); - var scheme = isAuthenticated - ? await authenticationSchemeProvider.GetDefaultForbidSchemeAsync() - : await authenticationSchemeProvider.GetDefaultChallengeSchemeAsync(); + var scheme = !handlerOptions.AuthenticationScheme.IsNullOrWhiteSpace() + ? await authenticationSchemeProvider.GetSchemeAsync(handlerOptions.AuthenticationScheme) + : isAuthenticated + ? await authenticationSchemeProvider.GetDefaultForbidSchemeAsync() + : await authenticationSchemeProvider.GetDefaultChallengeSchemeAsync(); if (scheme != null) { + var handlers = httpContext.RequestServices.GetRequiredService(); var handler = await handlers.GetHandlerAsync(httpContext, scheme.Name); if (handler != null) { From 9de6722b941c94e2b67e8bb70a0b803b4a800366 Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 1 Sep 2021 14:13:10 +0800 Subject: [PATCH 3/6] Update DefaultAbpAuthorizationExceptionHandler.cs --- .../DefaultAbpAuthorizationExceptionHandler.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultAbpAuthorizationExceptionHandler.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultAbpAuthorizationExceptionHandler.cs index de2a059715..3bbe5c5914 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultAbpAuthorizationExceptionHandler.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultAbpAuthorizationExceptionHandler.cs @@ -13,11 +13,10 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling { public virtual async Task HandleAsync(AbpAuthorizationException exception, HttpContext httpContext) { - var isAuthenticated = httpContext.User.Identity?.IsAuthenticated ?? false; - var handlerOptions = httpContext.RequestServices.GetRequiredService>().Value; if (handlerOptions.UseAuthenticationScheme) { + var isAuthenticated = httpContext.User.Identity?.IsAuthenticated ?? false; var authenticationSchemeProvider = httpContext.RequestServices.GetRequiredService(); var scheme = !handlerOptions.AuthenticationScheme.IsNullOrWhiteSpace() ? await authenticationSchemeProvider.GetSchemeAsync(handlerOptions.AuthenticationScheme) From a4108ec53219b4bbb56dae4420785f8119495c4c Mon Sep 17 00:00:00 2001 From: maliming Date: Thu, 2 Sep 2021 10:19:53 +0800 Subject: [PATCH 4/6] Throw an exception if there is no scheme found. --- ...DefaultAbpAuthorizationExceptionHandler.cs | 54 +++++++++++++------ 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultAbpAuthorizationExceptionHandler.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultAbpAuthorizationExceptionHandler.cs index 3bbe5c5914..685c2a73bd 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultAbpAuthorizationExceptionHandler.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultAbpAuthorizationExceptionHandler.cs @@ -18,30 +18,54 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling { var isAuthenticated = httpContext.User.Identity?.IsAuthenticated ?? false; var authenticationSchemeProvider = httpContext.RequestServices.GetRequiredService(); - var scheme = !handlerOptions.AuthenticationScheme.IsNullOrWhiteSpace() - ? await authenticationSchemeProvider.GetSchemeAsync(handlerOptions.AuthenticationScheme) - : isAuthenticated - ? await authenticationSchemeProvider.GetDefaultForbidSchemeAsync() - : await authenticationSchemeProvider.GetDefaultChallengeSchemeAsync(); - if (scheme != null) + AuthenticationScheme scheme = null; + + if (!handlerOptions.AuthenticationScheme.IsNullOrWhiteSpace()) + { + scheme = await authenticationSchemeProvider.GetSchemeAsync(handlerOptions.AuthenticationScheme); + if (scheme == null) + { + throw new AbpException($"No authentication scheme named {handlerOptions.AuthenticationScheme} was found."); + } + } + else { - var handlers = httpContext.RequestServices.GetRequiredService(); - var handler = await handlers.GetHandlerAsync(httpContext, scheme.Name); - if (handler != null) + if (isAuthenticated) { - if (isAuthenticated) + scheme = await authenticationSchemeProvider.GetDefaultForbidSchemeAsync(); + if (scheme == null) { - await handler.ForbidAsync(null); + throw new AbpException($"There was no DefaultForbidScheme found."); } - else + } + else + { + scheme = await authenticationSchemeProvider.GetDefaultChallengeSchemeAsync(); + if (scheme == null) { - await handler.ChallengeAsync(null); + throw new AbpException($"There was no DefaultChallengeScheme found."); } - - return true; } } + + var handlers = httpContext.RequestServices.GetRequiredService(); + var handler = await handlers.GetHandlerAsync(httpContext, scheme.Name); + if (handler == null) + { + throw new AbpException($"No handler of {scheme.Name} was found."); + } + + if (isAuthenticated) + { + await handler.ForbidAsync(null); + } + else + { + await handler.ChallengeAsync(null); + } + + return true; } return false; From aadb5343d28e728baccac8c74fe45e069be376c4 Mon Sep 17 00:00:00 2001 From: maliming Date: Thu, 2 Sep 2021 10:27:02 +0800 Subject: [PATCH 5/6] Update AbpAuthorizationExceptionHandlerOptions.cs --- .../AbpAuthorizationExceptionHandlerOptions.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpAuthorizationExceptionHandlerOptions.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpAuthorizationExceptionHandlerOptions.cs index 8adc4383d0..2be86dbebe 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpAuthorizationExceptionHandlerOptions.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpAuthorizationExceptionHandlerOptions.cs @@ -4,9 +4,6 @@ { public bool UseAuthenticationScheme { get; set; } - /// - /// Use default forbid/challenge scheme if this is not specified. - /// public string AuthenticationScheme { get; set; } public AbpAuthorizationExceptionHandlerOptions() From a112586110037c0bf5eb97e0edab28ccae27fc84 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 7 Sep 2021 13:39:36 +0800 Subject: [PATCH 6/6] Use authentication scheme by default. --- .../ExceptionHandling/AbpExceptionFilter.cs | 22 +++--- .../AbpExceptionPageFilter.cs | 22 +++--- ...AbpAuthorizationExceptionHandlerOptions.cs | 7 -- .../AbpExceptionHandlingMiddleware.cs | 43 ++++++----- ...DefaultAbpAuthorizationExceptionHandler.cs | 75 +++++++++---------- .../IAbpAuthorizationExceptionHandler.cs | 2 +- ...horizationExceptionTestController_Tests.cs | 1 - ...AbpAuthorizationExceptionTestPage_Tests.cs | 1 - 8 files changed, 76 insertions(+), 97 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs index b1ce1dda92..9631e94da4 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs @@ -77,20 +77,18 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling if (context.Exception is AbpAuthorizationException) { - if (await context.HttpContext.RequestServices.GetRequiredService() - .HandleAsync(context.Exception.As(), context.HttpContext)) - { - context.Exception = null; //Handled! - return; - } + await context.HttpContext.RequestServices.GetRequiredService() + .HandleAsync(context.Exception.As(), context.HttpContext); } + else + { + context.HttpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true"); + context.HttpContext.Response.StatusCode = (int) context + .GetRequiredService() + .GetStatusCode(context.HttpContext, context.Exception); - context.HttpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true"); - context.HttpContext.Response.StatusCode = (int) context - .GetRequiredService() - .GetStatusCode(context.HttpContext, context.Exception); - - context.Result = new ObjectResult(new RemoteServiceErrorResponse(remoteServiceErrorInfo)); + context.Result = new ObjectResult(new RemoteServiceErrorResponse(remoteServiceErrorInfo)); + } context.Exception = null; //Handled! } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs index e6ebc235d1..2a8c136fbc 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs @@ -88,20 +88,18 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling if (context.Exception is AbpAuthorizationException) { - if (await context.HttpContext.RequestServices.GetRequiredService() - .HandleAsync(context.Exception.As(), context.HttpContext)) - { - context.Exception = null; //Handled! - return; - } + await context.HttpContext.RequestServices.GetRequiredService() + .HandleAsync(context.Exception.As(), context.HttpContext); } + else + { + context.HttpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true"); + context.HttpContext.Response.StatusCode = (int) context + .GetRequiredService() + .GetStatusCode(context.HttpContext, context.Exception); - context.HttpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true"); - context.HttpContext.Response.StatusCode = (int) context - .GetRequiredService() - .GetStatusCode(context.HttpContext, context.Exception); - - context.Result = new ObjectResult(new RemoteServiceErrorResponse(remoteServiceErrorInfo)); + context.Result = new ObjectResult(new RemoteServiceErrorResponse(remoteServiceErrorInfo)); + } context.Exception = null; //Handled! } diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpAuthorizationExceptionHandlerOptions.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpAuthorizationExceptionHandlerOptions.cs index 2be86dbebe..7c21e2ea63 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpAuthorizationExceptionHandlerOptions.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpAuthorizationExceptionHandlerOptions.cs @@ -2,13 +2,6 @@ { public class AbpAuthorizationExceptionHandlerOptions { - public bool UseAuthenticationScheme { get; set; } - public string AuthenticationScheme { get; set; } - - public AbpAuthorizationExceptionHandlerOptions() - { - UseAuthenticationScheme = true; - } } } diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs index b4aa9745b5..51c78b4a83 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs @@ -68,30 +68,29 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling if (exception is AbpAuthorizationException) { - if (await httpContext.RequestServices.GetRequiredService() - .HandleAsync(exception.As(), httpContext)) - { - return; - } + await httpContext.RequestServices.GetRequiredService() + .HandleAsync(exception.As(), httpContext); } - - var errorInfoConverter = httpContext.RequestServices.GetRequiredService(); - var statusCodeFinder = httpContext.RequestServices.GetRequiredService(); - var jsonSerializer = httpContext.RequestServices.GetRequiredService(); - var options = httpContext.RequestServices.GetRequiredService>().Value; - - httpContext.Response.Clear(); - httpContext.Response.StatusCode = (int)statusCodeFinder.GetStatusCode(httpContext, exception); - httpContext.Response.OnStarting(_clearCacheHeadersDelegate, httpContext.Response); - httpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true"); - - await httpContext.Response.WriteAsync( - jsonSerializer.Serialize( - new RemoteServiceErrorResponse( - errorInfoConverter.Convert(exception, options.SendExceptionsDetailsToClients) + else + { + var errorInfoConverter = httpContext.RequestServices.GetRequiredService(); + var statusCodeFinder = httpContext.RequestServices.GetRequiredService(); + var jsonSerializer = httpContext.RequestServices.GetRequiredService(); + var options = httpContext.RequestServices.GetRequiredService>().Value; + + httpContext.Response.Clear(); + httpContext.Response.StatusCode = (int)statusCodeFinder.GetStatusCode(httpContext, exception); + httpContext.Response.OnStarting(_clearCacheHeadersDelegate, httpContext.Response); + httpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true"); + + await httpContext.Response.WriteAsync( + jsonSerializer.Serialize( + new RemoteServiceErrorResponse( + errorInfoConverter.Convert(exception, options.SendExceptionsDetailsToClients) + ) ) - ) - ); + ); + } } private Task ClearCacheHeaders(object state) diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultAbpAuthorizationExceptionHandler.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultAbpAuthorizationExceptionHandler.cs index 685c2a73bd..87bc653092 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultAbpAuthorizationExceptionHandler.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultAbpAuthorizationExceptionHandler.cs @@ -11,64 +11,57 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling { public class DefaultAbpAuthorizationExceptionHandler : IAbpAuthorizationExceptionHandler, ITransientDependency { - public virtual async Task HandleAsync(AbpAuthorizationException exception, HttpContext httpContext) + public virtual async Task HandleAsync(AbpAuthorizationException exception, HttpContext httpContext) { var handlerOptions = httpContext.RequestServices.GetRequiredService>().Value; - if (handlerOptions.UseAuthenticationScheme) - { - var isAuthenticated = httpContext.User.Identity?.IsAuthenticated ?? false; - var authenticationSchemeProvider = httpContext.RequestServices.GetRequiredService(); + var isAuthenticated = httpContext.User.Identity?.IsAuthenticated ?? false; + var authenticationSchemeProvider = httpContext.RequestServices.GetRequiredService(); - AuthenticationScheme scheme = null; + AuthenticationScheme scheme = null; - if (!handlerOptions.AuthenticationScheme.IsNullOrWhiteSpace()) + if (!handlerOptions.AuthenticationScheme.IsNullOrWhiteSpace()) + { + scheme = await authenticationSchemeProvider.GetSchemeAsync(handlerOptions.AuthenticationScheme); + if (scheme == null) + { + throw new AbpException($"No authentication scheme named {handlerOptions.AuthenticationScheme} was found."); + } + } + else + { + if (isAuthenticated) { - scheme = await authenticationSchemeProvider.GetSchemeAsync(handlerOptions.AuthenticationScheme); + scheme = await authenticationSchemeProvider.GetDefaultForbidSchemeAsync(); if (scheme == null) { - throw new AbpException($"No authentication scheme named {handlerOptions.AuthenticationScheme} was found."); + throw new AbpException($"There was no DefaultForbidScheme found."); } } else { - if (isAuthenticated) - { - scheme = await authenticationSchemeProvider.GetDefaultForbidSchemeAsync(); - if (scheme == null) - { - throw new AbpException($"There was no DefaultForbidScheme found."); - } - } - else + scheme = await authenticationSchemeProvider.GetDefaultChallengeSchemeAsync(); + if (scheme == null) { - scheme = await authenticationSchemeProvider.GetDefaultChallengeSchemeAsync(); - if (scheme == null) - { - throw new AbpException($"There was no DefaultChallengeScheme found."); - } + throw new AbpException($"There was no DefaultChallengeScheme found."); } } + } - var handlers = httpContext.RequestServices.GetRequiredService(); - var handler = await handlers.GetHandlerAsync(httpContext, scheme.Name); - if (handler == null) - { - throw new AbpException($"No handler of {scheme.Name} was found."); - } - - if (isAuthenticated) - { - await handler.ForbidAsync(null); - } - else - { - await handler.ChallengeAsync(null); - } - - return true; + var handlers = httpContext.RequestServices.GetRequiredService(); + var handler = await handlers.GetHandlerAsync(httpContext, scheme.Name); + if (handler == null) + { + throw new AbpException($"No handler of {scheme.Name} was found."); } - return false; + if (isAuthenticated) + { + await handler.ForbidAsync(null); + } + else + { + await handler.ChallengeAsync(null); + } } } } diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/IAbpAuthorizationExceptionHandler.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/IAbpAuthorizationExceptionHandler.cs index 9f95c18f28..efcbf9c7ea 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/IAbpAuthorizationExceptionHandler.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/IAbpAuthorizationExceptionHandler.cs @@ -6,6 +6,6 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling { public interface IAbpAuthorizationExceptionHandler { - Task HandleAsync(AbpAuthorizationException exception, HttpContext httpContext); + Task HandleAsync(AbpAuthorizationException exception, HttpContext httpContext); } } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpAuthorizationExceptionTestController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpAuthorizationExceptionTestController_Tests.cs index 6dd4a97d7c..aa0e6b5557 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpAuthorizationExceptionTestController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpAuthorizationExceptionTestController_Tests.cs @@ -34,7 +34,6 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling services.Configure(options => { - options.UseAuthenticationScheme = true; options.AuthenticationScheme = "Cookie"; }); } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpAuthorizationExceptionTestPage_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpAuthorizationExceptionTestPage_Tests.cs index f3bf1cca6d..6bc37c19e4 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpAuthorizationExceptionTestPage_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpAuthorizationExceptionTestPage_Tests.cs @@ -34,7 +34,6 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling services.Configure(options => { - options.UseAuthenticationScheme = true; options.AuthenticationScheme = "Cookie"; }); }