Web Api Custom Authorize Attribute Properties

16,406

Solution 1

The way Web API works is that the authorize attribute is called for the parent scope, in this case the controller, and the override (authorize attribute on the action) needs to be done manually (Please correct me if I'm wrong).

Therefore a solution could look like the following:

public class AuthorizeVerifiedUsersAttribute : AuthorizeAttribute
{
  (...)

  protected override bool IsAuthorized(HttpActionContext actionContext)
  {

     if (HttpContext.Current.User.Identity.IsAuthenticated)
     {
        //retrieve controller action's authorization attributes
        var authorizeAttributes = actionContext.ActionDescriptor.GetCustomAttributes<AuthorizeVerifiedUsersAttribute>();

        //check controller and action BypassValidation value
        if (BypassValidation || 
            actionAttributes.Count > 0 && actionAttributes.Any(x => x.BypassValidation))
        {
            return true;
        }
        else
        {
          //return false if user is unverified
        }

        return base.IsAuthorized(actionContext);
    }
 }

Solution 2

A bit too late, but for other users with similar problems: in Web API 2 you can override all previous authorization attributes (global authorization filters, controller authorization attributes, etc.) using "OverrideAuthorization" and afterwards just use the Authorize attribute, without specifying the role. The default behavior of the Authorize attribute is just to check if the user is authenticated.

In this case:

[YourCustomAuthorize]
public class UserProfileController : ApiController
{
    [OverrideAuthorization]
    [Authorize]
    public bool Verify(string verificationCode)
    {
    // TODO
    }
}
Share:
16,406

Related videos on Youtube

JCS
Author by

JCS

Updated on September 15, 2022

Comments

  • JCS
    JCS over 1 year

    I'm trying to extend he default Web Api authorize attribute to allow authenticated users to have access to a set of actions even though they are not registered in the application (e.g., they don't have a role).

     public class AuthorizeVerifiedUsersAttribute : AuthorizeAttribute
        {
            /// <summary>
            /// Gets or sets the authorized roles.
            /// </summary>
            public new string Roles { get { return base.Roles; } set { base.Roles = value; } }
    
            /// <summary>
            ///  Gets or sets the authorized users.
            /// </summary>
            public new string Users { get { return base.Users; } set { base.Users = value; } }
    
            private bool _bypassValidation;
            /// <summary>
            /// Gets of sets a controller or an action as an authorization exception
            /// </summary>
            public virtual bool BypassValidation
            {
                get
                {
                    Debug.WriteLine("get:" + TypeId.GetHashCode() + " " + _bypassValidation);
                    return _bypassValidation;
                }
                set
                {
                    Debug.WriteLine("set:" + TypeId.GetHashCode() + " " + value);
                    _bypassValidation = value;
                }
            }
    
            protected override bool IsAuthorized(System.Web.Http.Controllers.HttpActionContext actionContext)
            {
                if (HttpContext.Current.User.Identity.IsAuthenticated)
                {
                    if (BypassValidation)
                    {
                        return true;
                    }
                    else
                    {
                       //return false if user is unverified
    
                    }
                }
    
                return base.IsAuthorized(actionContext);
            }
        }
    

    And it is being used like this:

     [AuthorizeVerifiedUsers]
     public class UserProfileController : ApiController
     {
    
        [AuthorizeVerifiedUsers(BypassValidation = true)]
        public bool Verify(string verificationCode)
        {}
     }
    

    So far this action is the only that is using the BypassValidation = true.

    The issue arises because the BypassValidation property is false for the action even though the Debug window - used in the BypassValidation property - shows the following:

    set:26833123 True set:39602703 True get:43424763 False get:43424763 False get:43424763 False //call that should have "True"...

    I noticed two things:

    • The TypeId (The unique identifier for the attribute) is different between the calls that have BypassValidation = true and the ones that have BypassValidation = false.
    • The id '43424763' doesn't have a corresponding set

    Any ideas?

    Thanks in advance, Joao

  • Omid-RH
    Omid-RH over 8 years
    what is actionAttributes? is it authorizeAttributes?
  • JCS
    JCS over 8 years
    No, it is the list of attributes used on the action