0
votes

As I know all the actions inside a controller decorated with an authorize attribute will take by default the same attribute value, ( if controller authorize attribute roles = admin for example, automatically all the actions that are not decorated with any attributes will take the same role = admin), but this logic is not working in my case

here my custom authorize details

 public class CustomAuthorize : AuthorizeAttribute
    {
        public string Url { get; set; }
        public string Claims { get; set; }

        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            if (!httpContext.User.Identity.IsAuthenticated)
            {
                return false;
            }
            else if (!string.IsNullOrWhiteSpace(Claims))
            {
                var claims = httpContext.GetOwinContext().Authentication.User.HasClaim(t => t.Type == "claim"
                && Claims.Split(',').Contains(t.Value));
                if (!claims)
                {
                    return false;
                }
                else
                    return true;
            }
            else if (!string.IsNullOrWhiteSpace(Roles))
            {
                var roles = httpContext.GetOwinContext().Authentication.User.HasClaim(t => t.Type == "role"
                && Roles.Split(',').Contains(t.Value));
                if (!roles)
                {
                    return false;
                }
                else
                    return true;
            }
            return base.AuthorizeCore(httpContext);
        }

        public bool IsAuthorized(string claim)
        {
            if (!string.IsNullOrEmpty(Claims))
                return Claims.Split(',').Contains(claim);
            return true;
        }

        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            if (!string.IsNullOrEmpty(Url))
                filterContext.Result = new RedirectResult(Url);
            else
                base.HandleUnauthorizedRequest(filterContext);
        }

    }

a helper method to check the authentication

 public static bool ActionIsAuthorized(this HtmlHelper helper, string actionName, string controllerName)
        {
            IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
            ControllerBase controller = factory.CreateController(helper.ViewContext.RequestContext, controllerName) as ControllerBase;
            var controllerContext = new ControllerContext(helper.ViewContext.RequestContext, controller);
            var controllerDescriptor = new ReflectedControllerDescriptor(controller.GetType());
            var actionDescriptor = controllerDescriptor.FindAction(controllerContext, actionName);
            AuthorizationContext authContext = new AuthorizationContext(controllerContext, actionDescriptor);
            foreach (var authAttribute in actionDescriptor
                .GetFilterAttributes(true)
                .Where(a => a is CustomAuthorize).Select(a => a as CustomAuthorize))
            {
                authAttribute.OnAuthorization(authContext);
                if (authContext.Result != null)
                    return false;
            }
            return true;
        }

and usage in the view as

@if(Html.ActionIsAuthorized("Index","Appointment", new {area="Employee"})){
    @Html.ActionLink("Appointments","Index","Appointment",new {area = "Employee"})
}

When I use the above code as below, it will not work ( the appointment link still shown )

[CustomAuthorize(Claims="Add Appointment",Url="~/Employee/Home/Login")]
public class AppointmentController: BaseController
{
      public ActionResult Index()
      {
          // code here
      }
}

while if I use it in the following way, it works

public class AppointmentController: BaseController
{

      [CustomAuthorize(Claims="Add Appointment",Url="~/Employee/Home/Login")]
      public ActionResult Index()
      {
          // code here
      }
}

can anyone tell me why the action does not take the attribute by default when i decorate the controller with? or I missed something maybe?

1
What do you mean by "doesn't work". Do you mean the code in the CustomAttribute does not execute on the "Index" method when you apply the attribute at the class level?granadaCoder
@granadaCoder it runs but doens't read the custom attribute values ( the function ActionIsAuthorized )Monah

1 Answers

2
votes

Looks like the problem is in your custom ActionIsAuthorized html helper. You are only looking for attributes on the action descriptor and not on the controller descriptor. So make sure that you also look in controllerDescriptor.GetCustomAttributes():

var actionAttributes = actionDescriptor.GetCustomAttributes(typeof(CustomAuthorize), true);
var controllerAttributes = controllerDescriptor.GetCustomAttributes(typeof(CustomAuthorize), true);
var attributes = actionAttributes.Concat(controllerAttributes).OfType<CustomAuthorize>().ToList();
foreach (var authAttribute in attributes)
{
    ...
}