Search code examples
angularasp.net-web-apiantiforgerytoken

angular2+web.api2: injecting anti forgery tokens from server side (not asp.net core)


Just wondering if there are any samples out there that show how to use the anti forgery token when building a rich client with angular2 that consumes data from a set of web api2 services which where built over .NET 4.5. The web api services were not built with asp.net core nor will they be updated during the next months.

What's the recommended approach for this kind of scenario?

Thanks,

Luis


Solution

  • using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Web;
    using System.Web.Helpers;
    using System.Web.Http.Controllers;
    using System.Web.Http.Filters;
    using System.Web.Mvc;
    using ActionFilterAttribute = System.Web.Http.Filters.ActionFilterAttribute;
    
    namespace NgxAntiforgeryWebApi.Providers
    {
        public class XsrfCookieGeneratorAttribute : ActionFilterAttribute
        {
            public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
            {
                var xsrfTokenCookie = new HttpCookie("XSRF-TOKEN")
                {
                    Value = ComputeXsrfTokenValue(),
                    HttpOnly = false // Now JavaScript is able to read the cookie
                };
                HttpContext.Current.Response.AppendCookie(xsrfTokenCookie);
            }
    
            private string ComputeXsrfTokenValue()
            {
                string cookieToken, formToken;
                AntiForgery.GetTokens(null, out cookieToken, out formToken);
                return $"{cookieToken}:{formToken}";
            }
        }
    
        public class XsrfTokensValidationAttribute : ActionFilterAttribute
        {
            public override void OnActionExecuting(HttpActionContext actionContext)
            {
                IEnumerable<string> headerValues;
                if (!actionContext.Request.Headers.TryGetValues("X-XSRF-TOKEN", out headerValues))
                {
                    actionContext.Response = new HttpResponseMessage(HttpStatusCode.BadRequest) { ReasonPhrase = "X-XSRF-TOKEN header is missing." };
                    return;
                }
    
                if (headerValues == null)
                {
                    actionContext.Response = new HttpResponseMessage(HttpStatusCode.BadRequest) { ReasonPhrase = "X-XSRF-TOKEN header value is empty." };
                    return;
                }
    
                var xsrfTokensValue = headerValues.FirstOrDefault();
                if (string.IsNullOrEmpty(xsrfTokensValue) || !xsrfTokensValue.Contains(":"))
                {
                    actionContext.Response = new HttpResponseMessage(HttpStatusCode.BadRequest) { ReasonPhrase = "X-XSRF-TOKEN header value is null." };
                    return;
                }
    
                var values = xsrfTokensValue.Split(':');
                if (values.Length != 2)
                {
                    actionContext.Response = new HttpResponseMessage(HttpStatusCode.BadRequest) { ReasonPhrase = "X-XSRF-TOKEN header value is malformed." };
                    return;
                }
    
                var cookieToken = values[0];
                var formToken = values[1];
    
                try
                {
                    AntiForgery.Validate(cookieToken, formToken);
                }
                catch (HttpAntiForgeryException ex)
                {
                    actionContext.Response = new HttpResponseMessage(HttpStatusCode.BadRequest) {  ReasonPhrase = ex.Message };
                }
            }
        }
    }
    

    XsrfCookieGeneratorAttribute creates xsrf cookies which are readable by JavaScript codes (Angular Codes) and XsrfTokensValidationAttribute does the server side validation.