I'm working inside of ConfigureServices of my Startup class. I want to run IsInRole() which I understand to be this method in order to populate an Action:
However, running:
System.Security.Principal.IPrincipal.IsInRole("BRV_Projects_Edit");
Is clearly not successful as this refers to an interface, not an instance implementing that interface?
My Question is, within the context of ConfigureService, where I am defining a custom attribute how can I access (inject?) the Principal of the current user.
Per the feedback above User.InRole is not accessible at this point in the pipeline but is accessible via the creation of an ActionFilterAttribute.
The ActionFilterAttribute makes available OnActionExecuting, Get User Name on Action Filter extremely similar to this post except with changes relevant to .net core
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.Controller is Controller controller)
{
controller.ViewBag.CanEdit = filterContext.HttpContext.User.IsInRole("group1");
Related
I'm looking for a good place in the ASP.NET Web API lifecycle To update a property in my User entity that is purposed to store the date and time the User last made a request. Obviously, I could just add the code to each of my Controller methods but I would prefer doing this in one place outside of my controllers.
Ideally I would have access to the User principal and could use its Identity property to get the user's ID so that I could retrieve and update my User entity using Entity Framework.
I am currently looking at using a DelegatingHandler implementation.
Can anyone suggest the place in the lifecycle where I should carry this out? A code example would be appreciated.
Create an ActionFilter:
public class LogActionFilter : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
// Do your work
}
}
Yes, but wouldn't I have to add the ActionFilter to each and every controller method?
No, you can apply it to the controller or to actions.
Alternatively, you can do the following and you will not have to apply it to every controller (sort of like a global filter):
[LogActionFilter ]
public class LogableApiController : ApiController
{
...
}
Then inherit that wherever you want.
And lastly, another option is to add to global filters by finding the App_Start/FilterConfig.cs and add:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new LogActionFilter());
}
So I have shown you how to apply it to action level, controller level, one or more controllers but not all controllers and then how to apply it to all controllers (global).
I would create an Attribute for your Controller to execute the update on your User Entity with an ActionFilter.
This example explain how to create an attribute for a controller method, it is the same way to do it: Custom Attribute above a controller function
b.e, your controller would be like this:
[SaveUserRequest]
public class HomeController : ApiController
I have a user search request object which looks like this:
UserSearchRequest
{
FirstName:"John",
LastName:"Smith",
Expand:["groups","devices"]
}
Expand is an optional parameter. I have validation which checks that the provided Expand parameters are within thin expected set of parameters. The problem is that if a client submits a request like this:
{
FirstName:"John",
LastName:"Smith",
Expand:1
}
By default Web API 2 will pass this request to the controller method with an Expand value of null. So the user won't know that he submitted a bad request and the controller won't be able to identify it as a bad request b/c null is a valid value for this property. Is there a way to override this default behavior?
Action filters are triggered before controller executes its logic. I will give a general idea of what you need to do to get you on the right track.
First requirement for ActionFilter is to create your own filter class by extending ActionFilterAttribute class.
The following is a sample for this
public class ValidateCustomModel : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
//Write your logic to check that all attributes are not null
}
}
Now onto the second step. This step will register your filter in WebApiConfig class so that the application will know that it has to pass requests to this filter wherever the attribute is used
config.Filters.Add(new ValidateModelAttribute());
Now the third step is to call the custom class as an attribute on the controller method that is being executed when user makes a request.
[ValidateModel]
Hope this helps you to customise it for your own logic. Happy coding.
My team and I are starting up a new website project in ASP .NET 5 and I'm trying to set up the basis of our user authentication and authorization policy.
So far, I've managed to use the [Authorize] and [AllowAnonymous] attributes to selectively define an authorization policy controllers or actions. The one thing I'm still struggling to achieve is defining a default authorization policy.
Bascially, I'd like every controller and action to behave as if they had an [Authorize] attribute by default, so that only actions specifically tagged as [AllowAnonymous] can be accessed by an anonymous user. Otherwise, we expect that, at some point, someone will forget to add an [Authorize] attribute to their controller and introduce vulnerabilities into the webapp.
It is my understanding that what I'm trying to do could be achieved in previous versions of ASP .NET by adding the following statement in FilterConfig.cs:
filters.Add(new AuthorizeAttribute());
... except that FilterConfig.cs no longer exists in MVC 6. According to How to register a global filter with mvc 6, asp.net 5 I can now access the global filters list using:
services.ConfigureMvc(options =>
{
options.Filters.Add(new YouGlobalActionFilter());
}
... tried it, looks fine, but now it's the AuthorizeAttribute filter that I can't seem to find.
For experimenting purposes I've tried to handcraft an equivalent to the AuthorizeAttribute filter and came up with the following:
public class LoginFilter: AuthorizeFilter
{
public LoginFilter(): base(new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build())
{
}
public override Task OnAuthorizationAsync(Microsoft.AspNet.Mvc.AuthorizationContext context)
{
if(!context.HttpContext.User.Identity.IsAuthenticated && context.ActionDescriptor is ControllerActionDescriptor)
{
var action = context.ActionDescriptor as ControllerActionDescriptor;
if(!AcceptAnonymous(action.ControllerTypeInfo) && !AcceptAnonymous(action.MethodInfo))
{
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
}
}
return base.OnAuthorizationAsync(context);
}
private static bool AcceptAnonymous(ICustomAttributeProvider o)
{
return o.IsDefined(typeof(AllowAnonymousAttribute), true);
}
}
This kinda works... I can add it to the global filters list, and it does reject queries coming from unauthenticated users unless the query is resolved to an action tagged [AllowsAnonymous].
However...
the AuthorizationPolicyBuilder thingy is ugly and misleading: it does not serve any purpose and is apparently ignored during the whole processing. The only reason I added it is that AuthorizeFilter requires an AuthorizationPolicy in its constructor. I guess, but haven't tried yet, that directly implementing IAsyncAuthorizationFilter would solve this particular issue
nothing in this code is specific to my webapp and the functionality was apparently provided in previous versions of the framework, so I'm willing to bet that there already is (or there will soon be) a component doing exactly the same thing, and I'd rather use a standard component from the framework than handcraft my own.
So, long story short, where has the AuthorizeAttribute filter gone? Or is there any functional equivalent I can use to make rejection of anonymous users the default behavior?
You can use Microsoft.AspNet.Mvc.AuthorizeFilter.
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Authorization;
services.ConfigureMvc(options =>
{
options.Filters.Add(new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build()));
});
If you need custom authorization requirements see this answer for more information.
There seems to be some weird behavior in ASP.NET Web API (4.0.30506) that I haven't witnessed before.
What I'm seeing is that the same action filter attribute instance is reused over Web API requests. This is especially a problem in case this attribute gets dependencies injected to it, since those dependencies might be specific to the web request. I'm aware that it's better for attributes to be passive, but my assumption was that action filter attributes where not cached.
I searched for any articles, blog posts or Microsoft change logs that described this and the reason behind this, but I couldn't find a single thing. That makes me wonder whether there is something wrong with my configuration that makes this happening. Thing is however, that I'm able to reproduce this issue in a new and empty Visual Studio 2012 Web API project.
What I did was create a new empty project using the Visual Studio 2012 ASP.NET MVC 4 Web Application project with the "Web API" template. It comes with the Web API 4.0.20710.0 NuGet package. After that I added the following attribute:
[DebuggerDisplay("{id}")]
public class TestFilterAttribute : System.Web.Http.Filters.ActionFilterAttribute {
private static readonly List<int> used = new List<int>();
private static int counter;
private readonly int id;
public TestFilterAttribute() {
this.id = Interlocked.Increment(ref counter);
}
public override void OnActionExecuting(HttpActionContext actionContext) {
// Just for testing: I would expect this line never to throw, but it does.
if (used.Contains(this.id)) throw new Exception("WAT?");
used.Add(this.id);
base.OnActionExecuting(actionContext);
}
}
And I add this attribute to the ValuesController (part of the default template):
public class ValuesController : ApiController {
// GET api/values
[TestFilterAttribute]
public IEnumerable<string> Get() {
return new string[] { "value1", "value2" };
}
// ...
}
Now when I start the project, go to the /api/values in the browser and refresh that page a few times, the "WAT?" exception is thrown.
Is this normal behavior of Web API and if so, what's the reasoning about this? Or Did I miss some memo about this change somewhere? Does this make Web API attributes extra unsuited for doing dependency injection? Or am I'm doing something wrong?
Web API is built on top of MVC, thus it uses a lot of it's functionality.
Attribute instance re-usability is part of the aggressive caching introduced by MVC 3. This means that the same Attribute instance will most likely be used with all the Actions it is applied on. MVC pipeline will do it's best at trying to treat your Attribute class like a Singleton.
Because the same Attribute instance is reused, it's Constructor is not called and id is not incremented. If, for example, you increment id inside OnActionExecuting, all will work well.
You can still do everything you want with your Attribute. You only need to keep in mind that you are not guaranteed to always get a new instance created. The constructor shouldn't contain anything but initial initialization.
public TestFilterAttribute() {
// Instance will be reused thus this will not be called for each Action
}
public override void OnActionExecuting(HttpActionContext actionContext) {
// Called on each Action
}
I have an existing site which has a base controller class for all of its controllers which overrides the implementation of OnAuthorization. In the simplest cut down form:
protected override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
//Do Stuff
}
This all works fine and well and does what it wants at the right time. I now want to add a new global authorization that will run before all other authorisation attributes. For test purposes this attribute looks like this:
public class TestFilterAttribute : FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
var text = "debug point";
return;
}
}
And is added to the Global Filters like this:
filters.Add(new TestFilterAttribute());
My problem is that the OnAuthorization of the controller always seems to run before my filter's one. Is there any way that I can change this? I've tried playing with the order property that you can set when adding it to the global filter collection but that doesn't seem to help.
I could probably move the logic of the Controller's OnAuthorization into a new filter attribute when order would probably be usable but I'd rather avoid major code restructuring if there is an easier way to do it.
I've been searching for information on the Controller.OnAuthorization method but the best I have found is http://msdn.microsoft.com/en-us/library/gg416513(v=vs.98).aspx which only talks about filters. I had assumed that they would work the same way on Controllers but they seem to be getting treated specially, in particular not respecting the order (not even int.MinValue gets in first so its not just that the controller has a very low order by default).
So any suggestions on how to get an auth filter to run as the very first thing?
The final solution used was to refactor the code. I took all of the methods that can be run on a filter attribute (eg OnAuthorization, OnActionExecuting, etc.) and moved them onto attributes named for the classes they came from. So the OnAuthorization from BasicController became the same method on BasicControllerAttribute.
These attributes were then applied to the controllers and the attributes are then inherited by all of the classes that subclass from BasicController which essentially maintains the same functionality.
However the attribute can have its Order set that allows you to play around with the running order however you want.
My takeaway from this was to never override those methods on the controller and to always use attributes. :)
I had a related problem with the Controller.OnAuthorization and the AuthorizationFilter.OnAuthorization methods order of execution.
The short answer is: you can't override that Controller.OnAuthorization
runs prior to other filters.
Detailed answer on the question 'why is it so?' is in the code from
ASP.NET MVC sources below.
There is also nice blog post on filter ordering.
Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
FilterProviders.cs
namespace System.Web.Mvc
{
public static class FilterProviders
{
static FilterProviders()
{
Providers = new FilterProviderCollection();
Providers.Add(GlobalFilters.Filters);
Providers.Add(new FilterAttributeFilterProvider());
Providers.Add(new ControllerInstanceFilterProvider());
}
public static FilterProviderCollection Providers { get; private set; }
}
}
ControllerInstanceFilterProvider.cs
using System.Collections.Generic;
namespace System.Web.Mvc
{
public class ControllerInstanceFilterProvider : IFilterProvider
{
public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
if (controllerContext.Controller != null)
{
// Use FilterScope.First and Order of Int32.MinValue to ensure controller instance methods always run first
yield return new Filter(controllerContext.Controller, FilterScope.First, Int32.MinValue);
}
}
}
}