Web API custom authentication filter

26,182

Solution 1

Suppose you thought that sending user name and password to every request is not good.Refer my below implementation with out user name and password, since we are don't send user name and password with every request.

public class AuthenticationFilter : AuthorizationFilterAttribute
    {
        /// <summary>
        /// read requested header and validated
        /// </summary>
        /// <param name="actionContext"></param>
        public override void OnAuthorization(HttpActionContext actionContext)
        {
            var identity = FetchFromHeader(actionContext);

            if(identity != null)
            {
                var securityService = actionContext.ControllerContext.Configuration.DependencyResolver.GetService(typeof(ILoginService)) as ILoginService;
                if (securityService.TokenAuthentication(identity))
                {
                    CurrentThread.SetPrincipal(new GenericPrincipal(new GenericIdentity(identity), null), null, null);
                }
                else
                {
                    actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
                    return;
                }
            }
            else
            {
                actionContext.Response = new HttpResponseMessage(HttpStatusCode.BadRequest);
                return;
            }
            base.OnAuthorization(actionContext);
        }

        /// <summary>
        /// retrive header detail from the request 
        /// </summary>
        /// <param name="actionContext"></param>
        /// <returns></returns>
        private string FetchFromHeader(HttpActionContext actionContext)
        {
            string requestToken = null;

            var authRequest = actionContext.Request.Headers.Authorization;
            if (authRequest != null && !string.IsNullOrEmpty(authRequest.Scheme) && authRequest.Scheme == "Basic")
                requestToken = authRequest.Parameter;

            return requestToken;
        }
    }

Solution 2

You can make this filter unit testable by injecting the service dependencies via property(property injection). For custom attributes, we don't want to pass the dependencies via constructor. We want the attribute easy to use. To rewrite what @Raj already started, it can look like this:

   public class AuthenticationFilter : AuthorizationFilterAttribute
    {
        [Dependency]
        public ILoginService LoginService { get; set; }

        /// <summary>
        /// read requested header and validated
        /// </summary>
        /// <param name="actionContext"></param>
        public override void OnAuthorization(HttpActionContext actionContext)
        {
            var identity = FetchFromHeader(actionContext);

            if (identity != null)
            {
                if (LoginService.TokenAuthentication(identity))
                {
                    CurrentThread.SetPrincipal(new GenericPrincipal(new GenericIdentity(identity), null), null, null);

                    //IPrincipal principal = new GenericPrincipal(new GenericIdentity(identity), new string[] { "myRole" });
                    //Thread.CurrentPrincipal = principal;
                    //HttpContext.Current.User = principal;             
                }
                else
                {
                    actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
                    return;
                }
            }
            else
            {
                actionContext.Response = new HttpResponseMessage(HttpStatusCode.BadRequest);
                return;
            }
            base.OnAuthorization(actionContext);
        }

        /// <summary>
        /// retrive header detail from the request 
        /// </summary>
        /// <param name="actionContext"></param>
        /// <returns></returns>
        private string FetchFromHeader(HttpActionContext actionContext)
        {
            string requestToken = null;

            var authRequest = actionContext.Request.Headers.Authorization;
            if (authRequest != null && !string.IsNullOrEmpty(authRequest.Scheme) && authRequest.Scheme == "Basic")
                requestToken = authRequest.Parameter;

            return requestToken;
        }
    }
Share:
26,182
beowulf
Author by

beowulf

Updated on July 09, 2022

Comments

  • beowulf
    beowulf almost 2 years

    I am trying to make a custom filter for my web api controllers part of a ASP.NET MVC 5 website/application to check the requests headers for a specific token which i have stored in the database. Most examples I found were containing user credentials and then the user was authenticated using identity. Not exactly what I am looking for.

    This is the tutorial I found and am currently following.

    The web API should only handle "external" HTTP calls, the website side will have its own controllers presently (but may be subject to change).

    This filter should interface with identity 2 system already present if possible.

    What I do is that I send user credentials then, assign a token to the user and then I want to use that token to authenticate the request. Is there a way I can just filter the request based on the token or do I need to use Owin identity and their token management. I am using a mobile client (currently iOS, will include android too) to make the calls. Any example or tutorial I could refer to ?

    The token is currently a random combination of alphanumeric characters and symbols.

    Thank you.

    P.S. I can post code snippets and stuff where needed.

    Edit: The HTTPRequests will be filtered based on whether they contain a token present within our database/system. Requests that do contain a token or are not present within our system will receive unauthorised error (401?)

  • Apple Yellow
    Apple Yellow over 3 years
    I am been error at ILoginService. How to fix this it? @RajA