Reputation: 126
I have an custom action filter like this :
public class MySecurityTest : ActionFilterAttribut{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//Do some security tests
base.OnActionExecuting(filterContext);
}
}
I add this to FilterConfig
for all the actions.but I need some actions work without it.
for now I use something like this :
public class MySecurityTest : ActionFilterAttribute
{
public bool CheckRules { get; set; }
public MySecurityTest(bool checkRules = true)
{
CheckRules = checkRules;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (CheckRules)
{
//Do some security tests
}
base.OnActionExecuting(filterContext);
}
}
and the usage :
[MySecurityTest(false)]
public ActionResult Index()
{
return View();
}
but how can build something like [AllowAnonymous]
attribute
best regards
Upvotes: 4
Views: 2329
Reputation: 169
To build something like [AllowAnonymous] filter, you can inherit IAllowAnonymousFilter or whatever filter of your choice, then you have to make validation in other filters eg custom authorization filter, if context.filter is IAllowAnonymousFilter
var filters = context.Filters;
for (var i = 0; i < filters.Count; i++)
{
if (filters[i] is IAllowAnonymousFilter)
{
return true;
}
}
example
public class AuthorizeAllAccessActionFilter : IAuthorizationFilter // or whatever filter
you inherit
{
...... ....
public void OnAuthorization(AuthorizationFilterContext context)
{
var filters = context.Filters;
for (var i = 0; i < filters.Count; i++)
{
if (filters[i] is IAllowAnonymousFilter) // or AnonymousAccessActionFilter
{
return ;
}
}
.... ....
.....
....
}
public class AnonymousAccessActionFilter : IAllowAnonymousFilter,
IAuthorizationFilter, IOrderedFilter
{
....
....
// do what everver implement you want
}
i choose to leave IOrderedFilter in the code because you may want to change the order of execution on the filter, since you will want this to be executed first
you can now use it like this
[AuthorizeAllAccess]
public class UsersController : ControllerBase
{
/// other action method
[AnonymousAccess(Order = int.MinValue)]
[HttpGet]
public async Task<IActionResult> GetUsers() {
}
}
Upvotes: 0
Reputation: 56869
You simply need to make another attribute and use .NET reflection to check for its existence.
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!HasMyIgnoreAttribute(filterContext))
{
//Do some security tests
}
base.OnActionExecuting(filterContext);
}
public bool HasMyIgnoreAttribute(ActionDescriptor actionDescriptor)
{
// Check if the attribute exists on the action method
bool existsOnMethod = actionDescriptor.IsDefined(typeof(MyIgnoreAttribute), false);
if (existsOnMethod)
{
return true;
}
// Check if the attribute exists on the controller
return actionDescriptor.ControllerDescriptor.IsDefined(typeof(MyIgnoreAttribute), false);
}
And then make a custom attribute to decorate your actions/controllers with.
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)]
public class MyIgnoreAttribute : Attribute
{
}
[MySecurity]
public class MyController
{
[MyIgnore]
public ActionResult Index()
{
return View();
}
public ActionResult About()
{
return View();
}
}
In general, it is best not to use ActionFilterAttribute
if you are using dependency injection, since attributes should contain no behavior as in this answer. You should also consider using an authorization filter (or AuthorizationAttribute-inherited class) rather than an action filter for security checks, since it is done earlier in the pipeline.
Upvotes: 5
Reputation: 1038930
but how can build something like [AllowAnonymous] attribute
Quite easy actually:
[AttributeUsage(AttributeTargets.Method)]
public class ExcludeMySecurityAttribute : Attribute
{
}
and then in your filter account for it:
public class MySecurityTest : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.ActionDescriptor.GetCustomAttributes(typeof(ExcludeMySecurityAttribute), true).Any())
{
// The controller action is decorated with the exclude attribute
// so you should probably do nothing here
}
else
{
// Do your security tests here
}
}
}
Now all that's left is decorate:
[ExcludeMySecurity]
public ActionResult Index()
{
return View();
}
Upvotes: 5