27

My understanding of ASP.NET MVC is that for authorizations I should use something like -

public class IPAuthorize : AuthorizeAttribute {

protected override bool AuthorizeCore(HttpContextBase httpContext) {
    //figure out if the ip is authorized 
    //and return true or false
}

But in Web API, there is no AuthorizeCore(..).

There is OnAuthorization(..) and the general advice for MVC is not to use OnAuthorization(..).

What should I use for custom authorizations in Web API?

tom
  • 1,822
  • 4
  • 25
  • 43

2 Answers2

44

Authorization is done in an authorization filter - that mean you derive from System.Web.Http.AuthorizeAttribute and implement the IsAuthorized method.

You don't implement authorization in a normal action filter because they run later in the pipeline than authorization filters.

You also don't implement authentication in a filter (like parsing a JWT) - this is done even earlier in an extensibility point called MessageHandler.

Caltor
  • 2,538
  • 1
  • 27
  • 55
leastprivilege
  • 18,196
  • 1
  • 34
  • 50
  • 3
    +1 This is the correct answer use System.Web.Http.AuthorizeAttribute. The only reason for grudgingly using an actionfilter for authorization is if you need access to the deserialised message body to make the authorization decision but this is rarely either needed or good practice. – Mark Jones Mar 01 '13 at 11:00
  • If I implement ip address authorization inheriting from AuthorizeAttribute, is it ok to override the OnAuthorization(..) - I have been reading that in MVC you advised not to. – tom Mar 01 '13 at 17:12
  • 1
    Instead of overriding OnAuthorization it is probably better to override IsAuthorized and/or HandleUnauthorizedRequest. These do most of the actual work. – Mike Wasson Mar 01 '13 at 18:01
  • But OnAuthorization seems to be the one that is called when I have code like this - [IPAddressRestrictionAuthorizeAttribute] public Customer GetCustomer(string id) – tom Mar 02 '13 at 17:52
  • 1
    Right - but if you look at OnAuthorization it calls IsAuthorized and HandleUnauthorizedRequest. http://aspnetwebstack.codeplex.com/SourceControl/changeset/view/4764b0111b91#src/System.Web.Http/AuthorizeAttribute.cs – Mike Wasson Mar 03 '13 at 16:59
  • 6
    On review, I completely agree. I am going to drop my answer so that the correct one flows to the top. Someone else vote for deletion so it can be removed. ;-) – Oppositional Mar 04 '13 at 04:50
  • I am glad I learned something new, wasn't aware AuthorizeAttribute was before ActionFilterAttribute in the pipeline. I knew it ran before execution entered the controller action. Thanks for helping me learn how to improve my approach. – Oppositional Mar 04 '13 at 04:56
  • Mike, this seems like a pretty common scenario, any chance we can get a good clarifying example in the Web API online documentation? Also, since authentication has already occurred (when the JWT is issued to the caller after it presents credentials), isn't inspection of the claims in the JWT technically an authorization check by the controller/attribute? – Oppositional Mar 04 '13 at 05:06
  • Yes - inspecting claims is authorization. I wrote about it here:http://leastprivilege.com/2012/10/26/using-claims-based-authorization-in-mvc-and-web-api/ – leastprivilege Mar 04 '13 at 08:41
  • Thanks for all the information Dominick, I appreciate your insights. – Oppositional Mar 04 '13 at 15:22
  • @MikeWasson So we need to override IsAuthorized and not OnAuthorized - if we want to do simple logic... ? – Royi Namir Oct 20 '14 at 15:23
  • Here is an example of a custom MessageHandler: https://weblog.west-wind.com/posts/2013/apr/30/a-webapi-basic-authentication-messagehandler – foldinglettuce Apr 25 '17 at 18:07
11

The method we use for is an custom ApiAuthorize attribute that inherits from System.Web.Http.AuthorizeAttribute. for example:

public class ApiAuthorizeAttribute : AuthorizeAttribute
{
    readonly CreditPointModelContext _ctx = new CreditPointModelContext();

    public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        if(Authorize(actionContext))
        {
            return;
        }
        HandleUnauthorizedRequest(actionContext);
    }

    protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        var challengeMessage = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
        challengeMessage.Headers.Add("WWW-Authenticate", "Basic");
        throw new HttpResponseException(challengeMessage);

    }

    private bool Authorize(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        try
        {
            //boolean logic to determine if you are authorized.  
            //We check for a valid token in the request header or cookie.


        }
        catch (Exception)
        {
            return false;
        }
    }
}
Gareth Suarez
  • 596
  • 1
  • 5
  • 14
  • 9
    You shouldn't override OnAuthorization - because you would be missing [AllowAnonymous] handling. – leastprivilege Mar 04 '13 at 10:20
  • 4
    I thought the reason you were authorizing in the first place was not to allow anonymous. Call me crazy, but that doesn't make any sense. – Damon Drake Dec 19 '13 at 20:13
  • 1
    Makes sense, however, I can't think of many reasons why you would want to allow Anonymous access to your API. In our case, we certainly don't want anyone getting data from our API without a valid authentication token. – Gareth Suarez Dec 24 '13 at 04:14
  • 8
    what about apis that provide anonymous services like reset password, register etc.? – mare Apr 16 '14 at 07:19
  • 3
    @mare Don't use authorization attribute with such calls !! – Pushpendra Aug 19 '15 at 07:45
  • 7
    @Pushpendra the purpose of allow anonymous is that you can assign the authorize attribute to the controller and then allow anonymous to the methods that you want to exclude from authorize. Otherwise you need authorize attribute on every action – jle Feb 22 '16 at 15:15