Action filters & Authorization Filters working

This commit is contained in:
Yishai Galatzer 2014-03-05 20:42:21 -08:00
parent 6fed92695b
commit 772f833dc9
10 changed files with 102 additions and 43 deletions

View File

@ -0,0 +1,35 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc;
namespace MvcSample.Filters
{
public class AgeEnhancerAttribute : ActionFilterAttribute
{
public async override Task Invoke(ActionFilterContext context, Func<Task> next)
{
object age = null;
if (context.ActionParameters.TryGetValue("age", out age))
{
if (age is int)
{
var intAge = (int) age;
if (intAge < 21)
{
intAge += 5;
}
else if (intAge > 30)
{
intAge = 29;
}
context.ActionParameters["age"] = intAge;
}
}
await next();
}
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc;
namespace MvcSample
{
public class PassThroughAttribute : AuthorizationFilterAttribute
{
public async override Task Invoke(AuthorizationFilterContext context, Func<Task> next)
{
await next();
}
}
}

View File

@ -1,14 +1,13 @@
using System; using Microsoft.AspNet.Mvc;
using System.Threading.Tasks; using MvcSample.Filters;
using Microsoft.AspNet.Mvc;
using MvcSample.Models; using MvcSample.Models;
namespace MvcSample namespace MvcSample
{ {
// Expected order in descriptor - object -> int -> string // Expected order in descriptor - object -> int -> string
// TODO: Add a real filter here // TODO: Add a real filter here
[ServiceFilter(typeof(object), Order = 1)] [ServiceFilter(typeof(PassThroughAttribute), Order = 1)]
[ServiceFilter(typeof(string))] [ServiceFilter(typeof(PassThroughAttribute))]
[PassThrough(Order = 0)] [PassThrough(Order = 0)]
[PassThrough(Order = 2)] [PassThrough(Order = 2)]
public class FiltersController : Controller public class FiltersController : Controller
@ -16,18 +15,13 @@ namespace MvcSample
private readonly User _user = new User() { Name = "User Name", Address = "Home Address" }; private readonly User _user = new User() { Name = "User Name", Address = "Home Address" };
// TODO: Add a real filter here // TODO: Add a real filter here
[ServiceFilter(typeof(int))] [ServiceFilter(typeof(PassThroughAttribute))]
public IActionResult Index() [AgeEnhancer]
public IActionResult Index(int age)
{ {
_user.Age = age;
return View("MyView", _user); return View("MyView", _user);
} }
} }
public class PassThroughAttribute : AuthorizationFilterAttribute
{
public async override Task Invoke(AuthorizationFilterContext context, Func<Task> next)
{
await next();
}
}
} }

View File

@ -4,5 +4,6 @@
{ {
public string Name { get; set; } public string Name { get; set; }
public string Address { get; set; } public string Address { get; set; }
public int Age { get; set; }
} }
} }

View File

@ -36,6 +36,8 @@ namespace MvcSample
var services = MvcServices.GetDefaultServices(configuration, _env); var services = MvcServices.GetDefaultServices(configuration, _env);
var serviceProvider = new ServiceProvider().Add(services); var serviceProvider = new ServiceProvider().Add(services);
serviceProvider.AddInstance<PassThroughAttribute>(new PassThroughAttribute());
var routes = new RouteCollection() var routes = new RouteCollection()
{ {
DefaultHandler = new MvcApplication(serviceProvider), DefaultHandler = new MvcApplication(serviceProvider),

View File

@ -12,7 +12,7 @@
<p><a href="http://asp.net" class="btn btn-primary btn-large">Learn more &raquo;</a></p> <p><a href="http://asp.net" class="btn btn-primary btn-large">Learn more &raquo;</a></p>
</div> </div>
<div class="row"> <div class="row">
<h3 title="@Model.Name" class="@nullValue">Hello @Model.Name!</h3> <h3 title="@Model.Name" class="@nullValue">Hello @Model.Name! Happy @Model.Age birthday.</h3>
<div class="col-md-4"> <div class="col-md-4">
<h2>Getting started</h2> <h2>Getting started</h2>

View File

@ -5,10 +5,13 @@ namespace Microsoft.AspNet.Mvc
{ {
public class ActionFilterContext public class ActionFilterContext
{ {
public ActionFilterContext(ActionContext actionContext, IDictionary<string, object> actionParameters) public ActionFilterContext(ActionContext actionContext,
IDictionary<string, object> actionParameters,
Type methodReturnType)
{ {
ActionContext = actionContext; ActionContext = actionContext;
ActionParameters = actionParameters; ActionParameters = actionParameters;
MethodReturnType = methodReturnType;
} }
public virtual IDictionary<string, object> ActionParameters { get; private set; } public virtual IDictionary<string, object> ActionParameters { get; private set; }
@ -17,6 +20,6 @@ namespace Microsoft.AspNet.Mvc
public virtual Type MethodReturnType { get; private set; } public virtual Type MethodReturnType { get; private set; }
public virtual object Result { get; set; } public virtual IActionResult Result { get; set; }
} }
} }

View File

@ -46,9 +46,6 @@ namespace Microsoft.AspNet.Mvc
var controllerAttributes = cd.ControllerTypeInfo.GetCustomAttributes(inherit: true).ToArray(); var controllerAttributes = cd.ControllerTypeInfo.GetCustomAttributes(inherit: true).ToArray();
var filtersFromController = GetOrderedFilterAttributes(controllerAttributes); var filtersFromController = GetOrderedFilterAttributes(controllerAttributes);
bool allowAnonymous = IsAnonymous(controllerAttributes);
bool allowAnonymous = IsAnonymous(controllerAttributes); bool allowAnonymous = IsAnonymous(controllerAttributes);
foreach (var methodInfo in cd.ControllerTypeInfo.DeclaredMethods) foreach (var methodInfo in cd.ControllerTypeInfo.DeclaredMethods)

View File

@ -66,21 +66,40 @@ namespace Microsoft.AspNet.Mvc
var parameterValues = await GetParameterValues(modelState); var parameterValues = await GetParameterValues(modelState);
var authZFilters = context.AuthorizationFilters; var authZFilters = context.AuthorizationFilters;
var authZEndPoint = new AuthorizationFilterEndPoint();
authZFilters.Add(authZEndPoint);
var authZContext = new AuthorizationFilterContext(_actionContext);
var authZPipeline = new FilterPipelineBuilder<AuthorizationFilterContext>(authZFilters, authZContext);
await authZPipeline.InvokeAsync(); bool authZPassed;
if (authZFilters != null && authZFilters.Count > 0)
if (authZContext.ActionResult == null &&
!authZContext.HasFailed &&
authZEndPoint.EndPointCalled)
{ {
var actionFilters = context.ActionFilters; var authZEndPoint = new AuthorizationFilterEndPoint();
authZFilters.Add(authZEndPoint);
var authZContext = new AuthorizationFilterContext(_actionContext);
var authZPipeline = new FilterPipelineBuilder<AuthorizationFilterContext>(authZFilters,
authZContext);
await authZPipeline.InvokeAsync();
if (authZContext.ActionResult == null &&
!authZContext.HasFailed &&
authZEndPoint.EndPointCalled)
{
actionResult = null;
}
else
{
actionResult = authZContext.ActionResult ?? new HttpStatusCodeResult(401);
}
}
else
{
actionResult = null;
}
if (actionResult == null)
{
var actionFilters = context.ActionFilters ?? new List<IActionFilter>();
var actionFilterContext = new ActionFilterContext(_actionContext, var actionFilterContext = new ActionFilterContext(_actionContext,
new Dictionary<string, object>()); parameterValues,
method.ReturnType);
// TODO: This is extremely temporary and is going to get soon replaced with the action executer // TODO: This is extremely temporary and is going to get soon replaced with the action executer
var actionEndPoint = new ReflectedActionFilterEndPoint(async (inArray) => method.Invoke(controller, inArray), var actionEndPoint = new ReflectedActionFilterEndPoint(async (inArray) => method.Invoke(controller, inArray),
@ -93,18 +112,12 @@ namespace Microsoft.AspNet.Mvc
await actionFilterPipeline.InvokeAsync(); await actionFilterPipeline.InvokeAsync();
object actionReturnValue = method.Invoke(controller, null); actionResult = (IActionResult)actionFilterContext.Result;
actionResult = _actionResultFactory.CreateActionResult(method.ReturnType, actionReturnValue, _actionContext);
}
else
{
actionResult = authZContext.ActionResult ?? new HttpStatusCodeResult(401);
} }
} }
} }
var actionResultFilters = context.ActionResultFilters; var actionResultFilters = context.ActionResultFilters ?? new List<IActionResultFilter>();
await actionResult.ExecuteResultAsync(_actionContext);
var actionResultFilterContext = new ActionResultFilterContext(_actionContext, actionResult); var actionResultFilterContext = new ActionResultFilterContext(_actionContext, actionResult);
var actionResultFilterEndPoint = new ActionResultFilterEndPoint(); var actionResultFilterEndPoint = new ActionResultFilterEndPoint();
actionResultFilters.Add(actionResultFilterEndPoint); actionResultFilters.Add(actionResultFilterEndPoint);

View File

@ -51,7 +51,7 @@ namespace Microsoft.AspNet.Mvc
yield return DescribeService<INestedProvider<ActionDescriptorProviderContext>, yield return DescribeService<INestedProvider<ActionDescriptorProviderContext>,
ReflectedActionDescriptorProvider>(configuration); ReflectedActionDescriptorProvider>(configuration);
yield return DescribeService<INestedProvider<ActionInvokerProviderContext>, yield return DescribeService<INestedProvider<ActionInvokerProviderContext>,
ActionInvokerProvider>(configuration); ReflectedActionInvokerProvider>(configuration);
yield return DescribeService<IModelMetadataProvider, DataAnnotationsModelMetadataProvider>(configuration); yield return DescribeService<IModelMetadataProvider, DataAnnotationsModelMetadataProvider>(configuration);
yield return DescribeService<IActionBindingContextProvider, DefaultActionBindingContextProvider>(configuration); yield return DescribeService<IActionBindingContextProvider, DefaultActionBindingContextProvider>(configuration);