Self Hosted Microservice using OWIN, WebApi to authenticate users

Hi Guys,

This time I created Self Hosted Microservice using OWIN, WebApi to authenticate users, this service will store the authentication token on a file and subsequent requests are compared against the stored token.

Hope you like it.

1) Create a console application as following





















2) Install following packages using Nuget 

Microsoft.AspNet.WebApi.OwinSelfHost
Microsoft.Owin
Microsoft.AspNet.Cors

3) Startup.cs 

using Microsoft.Owin;
using Microsoft.Owin.Security.OAuth;
using Owin;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;

namespace SelfHosted.MicroService
{
    public class Startup
    {
        // This code configures Web API. The Startup class is specified as a type
        // parameter in the WebApp.Start method.
        public void Configuration(IAppBuilder appBuilder)
        {
            // Configure Web API for self-host. 
            HttpConfiguration config = new HttpConfiguration();
            config.EnableCors();
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            config.Formatters.JsonFormatter.SupportedMediaTypes
    .Add(new MediaTypeHeaderValue("text/html"));

            ConfigureOAuth(appBuilder);
            appBuilder.UseWebApi(config);
        }

        public void ConfigureOAuth(IAppBuilder app)
        {
            OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
            {
                AllowInsecureHttp = true,
                TokenEndpointPath = new PathString("/token"),
                AccessTokenExpireTimeSpan = TimeSpan.FromSeconds(10),
                Provider = new SimpleAuthorizationServerProvider()


            };



            // Token Generation
            app.UseOAuthAuthorizationServer(OAuthServerOptions);
            app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());


        }
    }
}

4) SimpleAuthorizationServerProvider 


using Microsoft.Owin.Security.OAuth;
using Newtonsoft.Json;
using SelfHosted.MicroService.Model;
using System;
using System.IO;
using System.Security.Claims;
using System.Threading.Tasks;

namespace SelfHosted.MicroService
{
    public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider
    {
        public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
            context.Validated();
        }

        public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {
            //Your authentication logic here
            context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });



        
            var user =
               UserService.GetUserByCredentials(context.UserName, context.Password);

            if (user != null)
            {

                var identity = new ClaimsIdentity(context.Options.AuthenticationType);
                identity.AddClaim(new Claim("sub", context.UserName));
                
                context.Validated(identity);


            }

            else
            {
                context.SetError("invalid_grant", "Invalid Username or password");
                return;



            }

        }

        public override Task TokenEndpointResponse(OAuthTokenEndpointResponseContext context)
        {
            //This can be written to a Database table too
            var dataFile = "c:\\temp\\accesstoken.txt";
            TokenStore data = new TokenStore() { token = context.AccessToken };
            File.WriteAllText(@dataFile, JsonConvert.SerializeObject(data));
            return base.TokenEndpointResponse(context);
            
        }

    }
}

5) Program.cs

using Microsoft.Owin.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SelfHosted.MicroService
{
    class Program
    {
        static void Main(string[] args)
        {
            string baseAddress = "http://127.0.0.1:8080/";

            // Start OWIN host 
            using (WebApp.Start(url: baseAddress))
            {
                Console.WriteLine("Service Listening at " + baseAddress);

                System.Threading.Thread.Sleep(-1);
            }
        }
    }
}

6) CustomAuthorizeAttribute.cs

using Newtonsoft.Json;
using SelfHosted.MicroService.Model;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;

namespace SelfHosted.MicroService
{
    public class CustomAuthorizeAttribute : AuthorizeAttribute
    {
        public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
        {
            if (AuthorizeRequest(actionContext))
            {
                return;
            }
            HandleUnauthorizedRequest(actionContext);
        }


        protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
        {
            //Code to handle unauthorized request
            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Forbidden);
            actionContext.Response.Headers.Add("AuthenticationStatus", "NotAuthorized");
         
            return;
        }

        private bool AuthorizeRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
        {
            //This can be read from the database table too
            var token = actionContext.Request.Headers.Authorization.Parameter;
            var dataFile = "c:\\temp\\accesstoken.txt";
            var data = File.ReadAllText(@dataFile);
            var response = JsonConvert.DeserializeObject<TokenStore>(data);
            if (response.token == token)
            {
                return true;
            }
            else
            {
                return false;
            }
           
        }
    }
}

7) MoviesController.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Cors;

namespace SelfHosted.MicroService
{
    public class Movie
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
    }

    [EnableCors(origins: "*", headers: "*", methods: "*")]
    public class MoviesController : ApiController
    {
        Movie[] movies = new Movie[]
        {
            new Movie { Id = 1, Name = "Skorpion King", Description = "Movie about a king"},
            new Movie { Id = 2, Name = "Fast & Furious", Description = "Cars, Girls and fun"},
            new Movie { Id = 3, Name = "Inception", Description = "Mind boggling sensation"},
            new Movie { Id = 4, Name = "Spider Man", Description = "Will Rock your world"}
        };

        // GET api/Websites 
        [CustomAuthorizeAttribute]
        public IEnumerable Get()
        {
            return movies;
        }

        // GET api/Websites/5 
        [CustomAuthorizeAttribute]
        public Movie Get(int id)
        {
            try
            {
                return movies[id];
            }
            catch (Exception e)
            {
                return new Movie();
            }
        }       

        
    }

}