mirror of https://github.com/abpframework/abp.git
Browse Source
Use ASP NET Core's AuthenticationScheme to handle AbpAuthorizationException.pull/10041/head
committed by
GitHub
17 changed files with 394 additions and 40 deletions
@ -0,0 +1,7 @@ |
|||||
|
namespace Volo.Abp.AspNetCore.ExceptionHandling |
||||
|
{ |
||||
|
public class AbpAuthorizationExceptionHandlerOptions |
||||
|
{ |
||||
|
public string AuthenticationScheme { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,67 @@ |
|||||
|
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 handlerOptions = httpContext.RequestServices.GetRequiredService<IOptions<AbpAuthorizationExceptionHandlerOptions>>().Value; |
||||
|
var isAuthenticated = httpContext.User.Identity?.IsAuthenticated ?? false; |
||||
|
var authenticationSchemeProvider = httpContext.RequestServices.GetRequiredService<IAuthenticationSchemeProvider>(); |
||||
|
|
||||
|
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 |
||||
|
{ |
||||
|
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) |
||||
|
{ |
||||
|
throw new AbpException($"There was no DefaultChallengeScheme found."); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
var handlers = httpContext.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>(); |
||||
|
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); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,69 @@ |
|||||
|
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<FakeUserClaims>(); |
||||
|
} |
||||
|
|
||||
|
protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) |
||||
|
{ |
||||
|
base.ConfigureServices(context, services); |
||||
|
|
||||
|
FakeExceptionSubscriber = Substitute.For<IExceptionSubscriber>(); |
||||
|
|
||||
|
services.AddSingleton(FakeExceptionSubscriber); |
||||
|
|
||||
|
services.Configure<AbpAuthorizationExceptionHandlerOptions>(options => |
||||
|
{ |
||||
|
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<ExceptionNotificationContext>()); |
||||
|
#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<ExceptionNotificationContext>()); |
||||
|
#pragma warning restore 4014
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,69 @@ |
|||||
|
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<FakeUserClaims>(); |
||||
|
} |
||||
|
|
||||
|
protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) |
||||
|
{ |
||||
|
base.ConfigureServices(context, services); |
||||
|
|
||||
|
_fakeExceptionSubscriber = Substitute.For<IExceptionSubscriber>(); |
||||
|
|
||||
|
services.AddSingleton(_fakeExceptionSubscriber); |
||||
|
|
||||
|
services.Configure<AbpAuthorizationExceptionHandlerOptions>(options => |
||||
|
{ |
||||
|
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<ExceptionNotificationContext>()); |
||||
|
#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<ExceptionNotificationContext>()); |
||||
|
#pragma warning restore 4014
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue