Getting User Id in Web Api handler when using Cachecow

1.7k views Asked by At

I have a MVC Web Api project and am logging all requests and responses using a MessageHandler. When an api request comes in, the bearer token in the header lets Asp.Net do its thing and authenticates that user. The message handler therefore knows who the user is and we write that to a log file.

Now, to speed up things I'm caching with Cachecow. So I've added the cachecow handler after the MessageHandler and when a second request comes in, from a caching point of view everything works fine. The controller code is never hit and the response is returned from the cache.

However, the MessageHandler does not have a value for the User.Identity so I cannot tell who made the request.

I need to log all requests and identify who made them even when the code in the controllers is not hit.

I think one workaround is to force the api requests to pass the bearer token and user id in the header. That way I can check the user id claim and use that to log who made the request.

protected override async Task OutgoingMessageAsync(string correlationId, string requestInfo, byte[] message, string responseTimeMilliseconds)
        {
            await Task.Run(() =>
                Debug.WriteLine(string.Format("{0} - Response: {1}\r\n{2}", correlationId, requestInfo, Encoding.UTF8.GetString(message))));

                    );
        }

User identity is null when getting response from cache.

?HttpContext.Current.User.Identity
{System.Security.Claims.ClaimsIdentity}
    [System.Security.Claims.ClaimsIdentity]: {System.Security.Claims.ClaimsIdentity}
    AuthenticationType: null
    IsAuthenticated: false
    Name: null

Any ideas?

3

There are 3 answers

0
Gabriel Ribeiro On

In authentication process, set object:

System.Threading.Thread.CurrentPrincipal = YourUserInformationObject;

This object need implement "System.Security.Principal.IPrincipal" Example

    public class YourUserInformation : IPrincipal
    {
       public Int32 Id { get; set; }
       public String NameUser { get; set; }

       public IIdentity Identity { get; private set; }


        public YourUserInformation()
        {
            this.Identity = new GenericIdentity(NameUser ?? "");
        }

        public bool IsInRole(string role) { return false; }
    }

In authentication process you save object in System.Threading.Thread.CurrentPrincipal

    public void Authentication(AuthorizationContext filterContext)
    {
       YourUserInformation user = YourMethodGetUserLogin();                

       System.Threading.Thread.CurrentPrincipal = user ;
    }
1
Gabriel Ribeiro On

try get in

System.Threading.Thread.CurrentPrincipal

0
Fehim On

Well you should create HttpContext from Request and there you will be able to use User.Identity object:

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var context = ((HttpContextBase)request.Properties["MS_HttpContext"]);
        var uname = username = context.User.Identity.Name;

        var response = await base.SendAsync(request, cancellationToken);

        return response;
    }

Also check this article: http://arcware.net/logging-web-api-requests/

Hoope this help!