Custom Async Action Filter for Web API 2

1.1k views Asked by At

I have a web api to consume the data coming from android mobile. This web api will consume the multi part file from along with the form data the web api request. I followed this article to archive.

[CustAuthAsync]
public async Task<HttpResponseMessage> SaveEHSInspectionData()
    {          
        try
        {             
            string root = HttpContext.Current.Server.MapPath("~/App_Data");
            MultipartFormDataStreamProvider provider = new MultipartFormDataStreamProvider(root); 
           //do stuff
           var res = await Request.Content.ReadAsMultipartAsync(provider);
           // DO SOME STUFF
        }
        catch (Exception exp)
        {

        }
        return Request.CreateResponse(HttpStatusCode.OK, result);
    }

I wanted to do the custom access validation for this web api, so implemented a filter to validate the request.

I have the filter like below

public class CustAuthAsyncAttribute : ActionFilterAttribute
{
    public override async Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
    {            
        InternalOnExecutingAsync(actionContext);
    }
}

The internal method like this

protected void InternalOnExecutingAsync(HttpActionContext actionContext)
        {
            var authValue = actionContext.Request.Headers;

if (authValue.Contains("CustomAccessToken"))
            {                
                string token = authValue.GetValues("CustomAccessToken").First();

                var result = // doing some decription

                if (result != null)
                {                    
                    bool validationResult = // validation with database
                    if (!validationResult)
                    {                        
                        actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
                        { ReasonPhrase = "Invalid token" };
                    }                    
                }
                else
                {
                    actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
                    { ReasonPhrase = "Invalid token" };
                }
            }
            else
            {
                actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
                { ReasonPhrase = "Unauthorized Request" };                
            }

These implementations are working fine in API Client Tools (Example: Postman) if the validation passes, allows the request to the method.

Postman Response screen shot

This is not working in mobile app, Saying the response message as Unauthorized Access. and not allowing the request to the method even the custom access validations are passed.

FYI : This method is working fine in mobile without filter

Help me to get this works in mobile app also.

Thanks in advance.

1

There are 1 answers

0
Fábio On

Your using the wrong type of filter to manage access. You should use an authorization filter. Besides you can't have an async method to authorize. You have to make the calling client wait for clearance. This may cause the side effects you're experiencing.

I'm not sure this has any to do with fact that it's a mobile application, however the authorization phase ir prior to the processing of the request. Verify that your are not using any other form of authorization in your project.

You should implement an authorization filter by inheriting AuthorizeAttribute and overriding IsAuthorized(HttpActionContext actionContext) method:

public class CustAuthAsync : AuthorizeAttribute
{
    public CustAuthAsync()
    {
        ///Some initialization if required. Otherwise, not necessary to declare the constructor..
    }

    protected override bool IsAuthorized(HttpActionContext actionContext)
    {
        var authValue = actionContext.Request.Headers;

        if (authValue.Contains("CustomAccessToken"))
        {
            string token = authValue.GetValues("CustomAccessToken").First();

            var result = // doing some decription

            if (result != null)
            {
                return //database validation
            }
            else
            {
                return false;
                //No need to create special unauthorized response. You should not hint the reason at this point. You can do this in the HandleUnauthorizedRequest method.
            }
        }
        else
        {
            return false;//No need to create special unauthorized response.
        }
    }
}

You can use this attribute to decorate your controllers. You can even pass parameter in the constructor for more granular control on access management, like a required role to access de controller.