@if (Roles.IsUserInRole("Administrators"))
{
<li>@Html.ActionLink("Create New", "Create")</li>
}
I have bounch of roles for users and many actions is accesible for more than one role.
It will be very hard to change that if statement in many places - is where a way to hide actionlink based only on Athorize(Roles="Administrator, SomethingElse")
?
Maybe there is a way to write custom helper that checks user premisions and using it instead of Html.Actionlink?
After some trial and error, the solution suggested here works. However sugested solution was for previous framework version.
Edited solution:
public static class AuthorizeActionLinkExtention
{
public static MvcHtmlString AuthorizeActionLink(this HtmlHelper helper, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
{
if (HasActionPermission(helper, actionName, controllerName))
return helper.ActionLink(linkText, actionName, controllerName, routeValues, htmlAttributes);
return MvcHtmlString.Empty;
}
public static MvcHtmlString AuthorizeActionLink(this HtmlHelper helper, string linkText, string actionName, string controllerName)
{
if (HasActionPermission(helper, actionName, controllerName))
return helper.ActionLink(linkText, actionName, controllerName);
return MvcHtmlString.Empty;
}
public static MvcHtmlString AuthorizeActionLink(this HtmlHelper helper, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
{
if (HasActionPermission(helper, actionName, controllerName))
return helper.ActionLink(linkText, actionName, controllerName, routeValues, htmlAttributes);
return MvcHtmlString.Empty;
}
static bool HasActionPermission(this HtmlHelper htmlHelper, string actionName, string controllerName)
{
ControllerBase controllerToLinkTo = string.IsNullOrEmpty(controllerName)
? htmlHelper.ViewContext.Controller
: GetControllerByName(htmlHelper, controllerName);
ControllerContext controllerContext = new ControllerContext(htmlHelper.ViewContext.RequestContext, controllerToLinkTo);
ReflectedControllerDescriptor controllerDescriptor = new ReflectedControllerDescriptor(controllerToLinkTo.GetType());
ActionDescriptor actionDescriptor = controllerDescriptor.FindAction(controllerContext, actionName);
return ActionIsAuthorized(controllerContext, actionDescriptor);
}
static bool ActionIsAuthorized(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
if (actionDescriptor == null)
return false;
AuthorizationContext authContext = new AuthorizationContext(controllerContext, actionDescriptor);
foreach (Filter authFilter in FilterProviders.Providers.GetFilters(authContext, actionDescriptor))
{
if (authFilter.Instance is System.Web.Mvc.AuthorizeAttribute)
{
((IAuthorizationFilter)authFilter.Instance).OnAuthorization(authContext);
if (authContext.Result != null)
return false;
}
}
return true;
}
static ControllerBase GetControllerByName(HtmlHelper helper, string controllerName)
{
IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
IController controller = factory.CreateController(helper.ViewContext.RequestContext, controllerName);
if (controller == null)
{
throw new InvalidOperationException(
string.Format(
CultureInfo.CurrentUICulture,
"Controller factory {0} controller {1} returned null",
factory.GetType(),
controllerName));
}
return (ControllerBase)controller;
}
}
I would write a custom action link helper:
public static class LinkExtensions
{
public static IHtmlString ActionLinkIfInRole(
this HtmlHelper htmlHelper,
string roles,
string linkText,
string action
)
{
if (!Roles.IsUserInRole(roles))
{
return MvcHtmlString.Empty;
}
return htmlHelper.ActionLink(linkText, action);
}
}
and then in my views:
@Html.ActionLinkIfInRole("Administrators", "Create New", "Create")
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