简体   繁体   中英

Custom Authorize works on action level but not on controller level

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?

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)
{
    ...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM