I read as many answers as I could for this, but they seem to fall short of one detail.
The trouble is when binding an action filter (with a service injected by controller) to a corresponding attribute, I've been unable to figure out how to pass parameter/property values from the attribute to its bound filter. Below is the code, and below that my intended fake-code:
Filter & Attribute
public class AuthorizationFilter : IAuthorizationFilter
{
private readonly IAuthorizationService _authorizationService;
private readonly UserRoles _requiredRoles; // Enum
public AuthorizationFilter(IAuthorizationService authorizationService, UserRoles requiredRoles)
{
_authorizationService = authorizationService;
_requiredRoles = requiredRoles;
}
public void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Session == null)
HandleUnauthorizedRequest(filterContext);
else {
var authorized = _authorizationService.IsUserInRole((UserSessionInfoViewModel) filterContext.HttpContext.Session["user"], _requiredRoles);
if (!authorized)
HandleUnauthorizedRequest(filterContext);
// else TODO: deal with cache...
}
}
}
public class RequireRolesAttribute : FilterAttribute
{
public readonly UserRoles RequiredRoles;
public RequireRolesAttribute(UserRoles requiredRoles)
{
RequiredRoles = requiredRoles;
}
}
Filter/Attribute Bindings
kernel.BindFilter<AuthorizationFilter>(FilterScope.Controller, 0)
.WhenControllerHas<RequireRolesAttribute>();
kernel.BindFilter<AuthorizationFilter>(FilterScope.Action, 0)
.WhenActionMethodHas<RequireRolesAttribute>();
This should make sure any controller/action decorated with [RolesRequired] is bound to the filter. So far so good. Now I want to declare via the attribute the roles (much like the stock AuthorizeAttribute) and pass those values onto the filter that actually does the authorization.
Intended/Fake Code:
[RequireRoles(UserRoles.Author)]
public ActionResult Index()
{
// blah
}
Specifically,
What does it take to inform the AuthorizationFilter of the roles? Can the filter/ninject access the arguments passed to the attribute's constructor? Can the filter/ninject pull them from the attributes public property?
For reference, these articles were a huge help, but don't answer this one thing:
Dependency Injection with Ninject and Filter attribute for asp.net mvc
Custom Authorization MVC 3 and Ninject IoC
B Z, Remo Gloor, others... how can I accomplish this?
I have figured it out (thanks to Remo's directions and documentation).
Use the appropriate .WithConstructorArgument extension whether you are binding to a Controller or Action filter. For example binding my action filter looks like this:
kernel.BindFilter<AuthorizationFilter>(FilterScope.Action, 0)
.WhenActionMethodHas<RequireRolesAttribute>()
.WithConstructorArgumentFromActionAttribute<RequireRolesAttribute>("requiredRoles", o => o.RequiredRoles);
Once I understood the Func<> signature, it all became clear. The best way I found to handle this was to
make the extension type-specific for my attribute
.WithConstructorArgumentFromActionAttribute<TAttribute>()
fetch the value from the callback object (your attribute) via lambda:
("argumentName", o => o.PropertyName)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With