Merge pull request #9150 from umbraco/netcore/feature/migrate-authorizedApiController-attributes
Netcore: Migrate authorized api controller attributes
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using Umbraco.Web.BackOffice.Filters;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Web.BackOffice.Filters;
|
||||
using Umbraco.Web.Common.Attributes;
|
||||
using Umbraco.Web.Common.Controllers;
|
||||
using Umbraco.Web.Common.Filters;
|
||||
@@ -14,13 +15,12 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// before their timeout expires.
|
||||
/// </remarks>
|
||||
[IsBackOffice]
|
||||
//[UmbracoUserTimeoutFilter] //TODO reintroduce
|
||||
[UmbracoUserTimeoutFilter]
|
||||
[UmbracoAuthorize]
|
||||
[DisableBrowserCache]
|
||||
[UmbracoWebApiRequireHttps]
|
||||
[CheckIfUserTicketDataIsStale]
|
||||
//[UnhandedExceptionLoggerConfiguration] //TODO reintroduce
|
||||
//[EnableDetailedErrors] //TODO reintroduce
|
||||
[MiddlewareFilter(typeof(UnhandledExceptionLoggerFilter))]
|
||||
public abstract class UmbracoAuthorizedApiController : UmbracoApiController
|
||||
{
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
|
||||
|
||||
namespace Umbraco.Web.BackOffice.Filters
|
||||
{
|
||||
/// <summary>
|
||||
/// Applies the UnhandledExceptionLoggerMiddleware to a specific controller
|
||||
/// when used with this attribute [MiddlewareFilter(typeof(UnhandledExceptionLoggerFilter))]
|
||||
/// The middleware will run in the filter pipeline, at the same stage as resource filters
|
||||
/// </summary>
|
||||
public class UnhandledExceptionLoggerFilter
|
||||
{
|
||||
public void Configure(IApplicationBuilder applicationBuilder)
|
||||
{
|
||||
applicationBuilder.UseMiddleware<UnhandledExceptionLoggerMiddleware>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.Filters
|
||||
{
|
||||
/// <summary>
|
||||
/// Logs any unhandled exception.
|
||||
/// </summary>
|
||||
public class UnhandledExceptionLoggerMiddleware : IMiddleware
|
||||
{
|
||||
private readonly ILogger<UnhandledExceptionLoggerMiddleware> _logger;
|
||||
|
||||
public UnhandledExceptionLoggerMiddleware(ILogger<UnhandledExceptionLoggerMiddleware> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
|
||||
{
|
||||
var requestUri = new Uri(context.Request.GetEncodedUrl(), UriKind.RelativeOrAbsolute);
|
||||
// If it's a client side request just call next and don't try to log anything
|
||||
if (requestUri.IsClientSideRequest())
|
||||
{
|
||||
await next(context);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Call the next middleware, and catch any errors that occurs in the rest of the pipeline
|
||||
try
|
||||
{
|
||||
await next(context);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Unhandled controller exception occurred for request '{RequestUrl}'", requestUri.AbsoluteUri);
|
||||
// Throw the error again, just in case it gets handled
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Extensions;
|
||||
using Umbraco.Web.BackOffice.Controllers;
|
||||
using Umbraco.Web.BackOffice.Filters;
|
||||
using Umbraco.Web.BackOffice.Routing;
|
||||
using Umbraco.Web.BackOffice.Security;
|
||||
using Umbraco.Web.BackOffice.Services;
|
||||
@@ -48,6 +49,7 @@ namespace Umbraco.Web.BackOffice.Runtime
|
||||
"~/"));
|
||||
|
||||
composition.RegisterUnique<IIconService, IconService>();
|
||||
composition.RegisterUnique<UnhandledExceptionLoggerMiddleware>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,7 +275,7 @@ namespace Umbraco.Extensions
|
||||
loggingConfiguration,
|
||||
configuration, out var ioHelper, out var hostingEnvironment, out var backOfficeInfo, out var profiler);
|
||||
|
||||
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
|
||||
var loggerFactory = services.BuildServiceProvider().GetService<ILoggerFactory>();
|
||||
|
||||
var umbracoVersion = new UmbracoVersion();
|
||||
var typeFinder = CreateTypeFinder(loggerFactory, profiler, webHostEnvironment, entryAssembly, typeFinderSettings);
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.Globalization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Web.Common.Filters
|
||||
{
|
||||
/// <summary>
|
||||
/// This will check if the user making the request is authenticated and if there's an auth ticket tied to the user
|
||||
/// we will add a custom header to the response indicating how many seconds are remaining for the
|
||||
/// user's session. This allows us to keep track of a user's session effectively in the back office.
|
||||
/// </summary>
|
||||
public class UmbracoUserTimeoutFilterAttribute : TypeFilterAttribute
|
||||
{
|
||||
public UmbracoUserTimeoutFilterAttribute() : base(typeof(UmbracoUserTimeoutFilter))
|
||||
{
|
||||
}
|
||||
|
||||
private class UmbracoUserTimeoutFilter : IActionFilter
|
||||
{
|
||||
public void OnActionExecuted(ActionExecutedContext context)
|
||||
{
|
||||
//this can occur if an error has already occurred.
|
||||
if (context.HttpContext.Response is null) return;
|
||||
|
||||
var remainingSeconds = context.HttpContext.User.GetRemainingAuthSeconds();
|
||||
context.HttpContext.Response.Headers.Add("X-Umb-User-Seconds", remainingSeconds.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
public void OnActionExecuting(ActionExecutingContext context)
|
||||
{
|
||||
// Noop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -237,8 +237,6 @@
|
||||
<Compile Include="WebApi\Filters\FeatureAuthorizeAttribute.cs" />
|
||||
<Compile Include="WebApi\SessionHttpControllerRouteHandler.cs" />
|
||||
<Compile Include="WebApi\UmbracoApiControllerTypeCollectionBuilder.cs" />
|
||||
<Compile Include="WebApi\UnhandedExceptionLoggerConfigurationAttribute.cs" />
|
||||
<Compile Include="WebApi\UnhandledExceptionLogger.cs" />
|
||||
<Compile Include="Runtime\WebInitialComponent.cs" />
|
||||
<Compile Include="Mvc\ControllerContextExtensions.cs" />
|
||||
<Compile Include="Mvc\DisableBrowserCacheAttribute.cs" />
|
||||
@@ -372,7 +370,6 @@
|
||||
<Compile Include="WebApi\UmbracoAuthorizeAttribute.cs" />
|
||||
<Compile Include="WebApi\UmbracoAuthorizedApiController.cs" />
|
||||
<Compile Include="WebApi\Filters\ValidationFilterAttribute.cs" />
|
||||
<Compile Include="WebApi\Filters\UmbracoUserTimeoutFilterAttribute.cs" />
|
||||
<Compile Include="Mvc\ControllerExtensions.cs" />
|
||||
<Compile Include="TypeLoaderExtensions.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs">
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Web.Http.Filters;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Web.Security;
|
||||
|
||||
namespace Umbraco.Web.WebApi.Filters
|
||||
{
|
||||
/// <summary>
|
||||
/// This will check if the request is authenticated and if there's an auth ticket present we will
|
||||
/// add a custom header to the response indicating how many seconds are remaining for the current
|
||||
/// user's session. This allows us to keep track of a user's session effectively in the back office.
|
||||
/// </summary>
|
||||
public sealed class UmbracoUserTimeoutFilterAttribute : ActionFilterAttribute
|
||||
{
|
||||
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
|
||||
{
|
||||
base.OnActionExecuted(actionExecutedContext);
|
||||
|
||||
//this can occur if an error has already occurred.
|
||||
if (actionExecutedContext.Response == null) return;
|
||||
|
||||
var httpContextAttempt = actionExecutedContext.Request.TryGetHttpContext();
|
||||
if (httpContextAttempt.Success)
|
||||
{
|
||||
|
||||
var ticket = httpContextAttempt.Result.GetUmbracoAuthTicket();
|
||||
if (ticket?.Properties.ExpiresUtc != null && ticket.Properties.ExpiresUtc.Value < DateTimeOffset.UtcNow)
|
||||
{
|
||||
var remainingSeconds = httpContextAttempt.Result.GetRemainingAuthSeconds();
|
||||
actionExecutedContext.Response.Headers.Add("X-Umb-User-Seconds", remainingSeconds.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,12 +21,12 @@ namespace Umbraco.Web.WebApi
|
||||
/// before their timeout expires.
|
||||
/// </remarks>
|
||||
[IsBackOffice]
|
||||
[UmbracoUserTimeoutFilter]
|
||||
// [UmbracoUserTimeoutFilter] has been migrated to netcore
|
||||
[UmbracoAuthorize]
|
||||
[DisableBrowserCache]
|
||||
// [UmbracoWebApiRequireHttps]
|
||||
// [CheckIfUserTicketDataIsStale]
|
||||
[UnhandedExceptionLoggerConfiguration]
|
||||
// [UnhandedExceptionLoggerConfiguration]
|
||||
[EnableDetailedErrors]
|
||||
public abstract class UmbracoAuthorizedApiController : UmbracoApiController
|
||||
{
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Http.Controllers;
|
||||
using System.Web.Http.ExceptionHandling;
|
||||
using System.Web.Http.Filters;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Web.WebApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds our unhandled exception logger to the controller's services
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Important to note that the <see cref="UnhandledExceptionLogger"/> will only be called if the controller has an ExceptionFilter applied
|
||||
/// to it, so to kill two birds with one stone, this class inherits from ExceptionFilterAttribute purely to force webapi to use the
|
||||
/// IExceptionLogger (strange)
|
||||
/// </remarks>
|
||||
public class UnhandedExceptionLoggerConfigurationAttribute : ExceptionFilterAttribute, IControllerConfiguration
|
||||
{
|
||||
public virtual void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
|
||||
{
|
||||
controllerSettings.Services.Add(typeof(IExceptionLogger), new UnhandledExceptionLogger());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using System.Web.Http.ExceptionHandling;
|
||||
using Umbraco.Web.Composing;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Umbraco.Web.WebApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to log unhandled exceptions in webapi controllers
|
||||
/// </summary>
|
||||
public class UnhandledExceptionLogger : ExceptionLogger
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public UnhandledExceptionLogger()
|
||||
: this(Current.Logger)
|
||||
{
|
||||
}
|
||||
|
||||
public UnhandledExceptionLogger(ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public override void Log(ExceptionLoggerContext context)
|
||||
{
|
||||
if (context != null && context.Exception != null)
|
||||
{
|
||||
var requestUrl = context.ExceptionContext?.ControllerContext?.Request?.RequestUri?.AbsoluteUri;
|
||||
var controllerType = context.ExceptionContext?.ActionContext?.ControllerContext?.Controller?.GetType();
|
||||
|
||||
_logger.LogError(context.Exception, "Unhandled controller exception occurred for request '{RequestUrl}'", requestUrl);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user