Reading every incoming request (URL) in ASP.NET WEB API

10,674

You can use message handlers from ASP.NET Web API. It is a typical security scenation, when you need to get some user token from query string, URL or HTTP Header

http://www.asp.net/web-api/overview/advanced/http-message-handlers

1.When you need simply to extract userId from URL, then use it as parameter for your Api method and ASP.NET WebAPI will do work for you, like

[HttpGet, Route("{userId}/roles")]      
public UserRoles GetUserRoles(string userId, [FromUri] bool isExternalUser = true)

It work for such request

http://.../15222/roles?isExternalUser=false

2.If it is security scenario, please refer to http://www.asp.net/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api Basically you will need some MessageHandler or you can use filter attributes as well, it is mechanism in ASP.NET Web API to intercept each call.

If you need to process each request then MessageHandler is your way. You need implement MessageHanler and then register it.

To say easily, typical MessageHandler is class derived from MessageHandler or DelegatingHandler with SendAsync method overriden:

class AuthenticationHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // Your code here
        return base.SendAsync(request, cancellationToken);
     }
}

And you need register it 

static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {                   
        // Other code for WebAPI registerations here
        config.MessageHandlers.Add(new AuthenticationHandler());            
    }
}

and call it from Global.asax.cs

WebApiConfig.Register(GlobalConfiguration.Configuration);

Some example dummy hypotetical implementation of such handler (here you need to imeplement your UidPrincipal from IPrincipal and UidIdentity from IIdentity)

public class AuthenticationHandler : DelegatingHandler
{       
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        try
        {
            var queryString = actionContext.Request.RequestUri.Query;
            var items = HttpUtility.ParseQueryString(queryString);
            var userId = items["uid"];

            // Here check your UID and maybe some token, just dummy logic
            if (userId == "D8CD2165-52C0-41E1-937F-054F24266B65")
            {           
                IPrincipal principal = new UidPrincipal(new UidIdentity(uid), null);

                // HttpContext exist only when hosting as asp.net web application in IIS or IISExpress
                if (HttpContext.Current != null)
                {
                    HttpContext.Current.User = principal;
                }
                else
                {
                    Thread.CurrentPrincipal = principal;
                }
                return base.SendAsync(request, cancellationToken);
            }
            catch (Exception ex)
            {
                this.Log().Warn(ex.ToString());
                return this.SendUnauthorizedResponse(ex.Message);
            }
        }
        else
        {
            return this.SendUnauthorizedResponse();
        }
        }
        catch (SecurityTokenValidationException)
        {
            return this.SendUnauthorizedResponse();
        }
    }
}

And lets access it from some ASP.NET WebApi method or some property in WebAPI class

var uid = ((UidIdentity)User.Identity).Uid
Share:
10,674
SharpCoder
Author by

SharpCoder

Updated on June 21, 2022

Comments

  • SharpCoder
    SharpCoder almost 2 years

    I was using ASP.NET MVC framework. In this framework, we checked every incoming request (url) for some key and assigned it to a property. We created a custom class which derived from Controller class & we override OnActionExecuting() to provide our custom logic.

    How can we achieve the same in ASP.NET WEB API?

    //Implementation from ASP.NET MVC
    
    public class ApplicationController : Controller
    {       
        public string UserID { get; set; }
    
        protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (!string.IsNullOrEmpty(Request.Params["uid"]))
                UserID = Request.Params["uid"];
    
            base.OnActionExecuting(filterContext);
        }    
    }
    

    What I have tried in ASP.NET WEB API: -- Though this is working, I wonder if this is the correct approach?

    Created a base controller

    public class BaseApiController : ApiController
        {
            public string UserID { get; set; }
        }
    

    Created another class which inherits ActionFilterAttribute class & I override OnActionExecuting()

    public class TokenFilterAttribute : ActionFilterAttribute
        {
           public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
                {
                    var queryString = actionContext.Request.RequestUri.Query;
                    var items = HttpUtility.ParseQueryString(queryString);
                    var userId = items["uid"];
    
                    ((MyApi.Data.Controllers.BaseApiController)(actionContext.ControllerContext.Controller)).UserID = userId;
    
    
                }
      }
    

    Now register this class

    public static void Register(HttpConfiguration config)
    {
        config.Filters.Add(new TokenFilterAttribute());
    } 
    
  • SharpCoder
    SharpCoder over 9 years
    Thank you for quick help. Before posting the question I was checking this URL and not sure how this will help in my case. Can you please give me more details.
  • Regfor
    Regfor over 9 years
    I've tried to add a little bit code and make it more clear for you. What is your use case? Why you need extract UserID from each request?
  • SharpCoder
    SharpCoder over 9 years
    Some of the request will have userId being passed as query string. All I want is to check every request & if the query string has userId, I will read it and assign it to UserID property in BaseController. BaseController will inherits from ApiController. And all my controllers will inherit from BaseController. Which will ensure UserID property is available to all controllers. Problem is DelegatingHandler is also a class, unlike IActionFilter interface which is available in ASP.NET MVC