Authenticate users with JWT (JSON Web Tokens) with .Net and TypeScript

When creating web applications, it is a common thing to provide a user login function.
And when creating user logins it is required to authenticate them probably using a token which contain the user session data and user role data.

When considering the token creation and authenticate it there are several ways and technologies to do and in this blog I would like to explain how to create token and validate it using JWT (JSON Web Tokens). Read about JWT from here

There are several packages in NuGet store that provide JWT features and in this article I'm going to use System.IdentityModel.Tokens.Jwt 



Install this in your project using the NuGet package manager.

Ok, now let's get started.

1.     Create token

Let's create a class to create token when user log in to the system. 
Create a hased key of SHA256 to use when crating the token. 

using System;
using System.Text;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;

private const string Secret = "your secret key"; (24 characters in length)
static JwtSecurityTokenHandler tokenhandler = null;

public static string GenerateToken(string Username, int Id, short TerminalId)
{
    try
    {
        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Secret));
        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

        var header = new JwtHeader(credentials);
        var payload = new JwtPayload
        {
            { "Username", Username },
            { "Id", Id.ToString() },
            { "TerminalId", TerminalId.ToString() },
            { "ExpireOn", DateTime.UtcNow.AddYears(1) }
        };

        var secToken = new JwtSecurityToken(header, payload);
        if (tokenhandler == null)
        {
            tokenhandler = new JwtSecurityTokenHandler();
        }
        tokenhandler = new JwtSecurityTokenHandler();

        var token = tokenhandler.WriteToken(secToken);
        return token;
    }
    catch (Exception ex)
    {
        Logger.Logger.LogError(ex);
        throw;
    }
}


        2. Class to managed logged users

In this scenario I have created a class to save the information about the logged users. So I don't have to retrieve those from the database every time. 

public sealed class LoggedUsers
{
    private static List<string> loggedUsers = null;

    public static void AddLoggedUser(string username)
    {
        if (loggedUsers == null)
        {
            loggedUsers = new List<string>();
        }

        if (!loggedUsers.Contains(username))
        {
            loggedUsers.Add(username);
        }
    }

    public static bool IsLoggedUser(string username)
    {
        if (loggedUsers.Contains(username))
        {
            return true;
        }
        return false;
    }
}

          3. Validate Token

This class will use to validate the created token.

public static bool IsTokenValid(string token)
{
    if (tokenhandler == null)
    {
        tokenhandler = new JwtSecurityTokenHandler();
    }
    var userToken = tokenhandler.ReadJwtToken(token);
    if (userToken != null && userToken.Payload != null)
    {
        if (string.IsNullOrEmpty(userToken.Payload["Username"].ToString())
            || string.IsNullOrEmpty(userToken.Payload["ExpireOn"].ToString()))
        {
            return false;
        }
        var isLoggedUser = LoggedUsers.IsLoggedUser(userToken.Payload["Username"].ToString());
        var tokenExpireOn = DateTime.Parse(userToken.Payload["ExpireOn"].ToString());
        if (isLoggedUser && tokenExpireOn > DateTime.Now)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    else
    {
        return false;
    }
}

     4. Custom Attribute to Authorize request

I have created a custom attribute so when the request comes with the token to the controller method, we can check the validation and authenticate user or we can deny the request.

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class AuthorizeUserAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var userToken = httpContext.Request.Headers["Authorization"];
        var tokenValid = UserTokenManager.IsTokenValid(userToken);
        if (!tokenValid)
        {
            httpContext.Response.AppendHeader("AuthorizeUser", "UnAuthorized");
        }
        return tokenValid;
    }
}

In .Net 4.7 I have found that the overriding method has been changed.
If you are using .Net 4.7 and upper, you have to use this as bellow:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
    public class AuthorizeUserAttribute : AuthorizeAttribute
    {
        protected override bool IsAuthorized(HttpActionContext httpContext)
try
            {
                var header = httpContext.Request.Headers;
                var authValue = httpContext.Request.Headers.Where(a => a.Key == "AuthToken").FirstOrDefault().Value;
                if (authValue != null)
                {
                    var token = authValue.First();
                    var tokenValid = TokenHandler.IsTokenValid(token);
                    if (!tokenValid)
                    {
                        if (httpContext.Response == null)
                            httpContext.Response = new HttpResponseMessage();
                        httpContext.Response.Headers.Add("AuthorizeUser", "UnAuthorized");
                    }
                    return tokenValid;
                }
                return true;
            }
            catch (Exception)
            {
                throw;
            }
        }
    }



     5. Save token in localstorage

When the token is created we have to store it in the front end because we have to send it with every request to authenticate the user. 
So I have saved it in the local storage.  

private LogIn(){
    let login = this.CreateLogInObject();
    self.userLogInService.LogIn(login, function (result: ResultObject) {
        if(result != null){
            if(result.State == 200 && result.ResultData != null){
                localStorage.setItem("Token", result.ResultData);
            }
        }
    });
}

      6. Send request to server with the token

We are all set now. From now onwards we have to send the token with every request within the ajax call when calling the server and we are going to send it within the header section off the request. 

public TestUserAuthentication = (callback: any) => {
    $.ajax({
        url: '/Login/TestUserAuthentication',
        type: 'GET',
        dataType: 'JSON',
        headers: {"Authorization": localStorage.getItem('Token')},
        success: function (data: ResultObject) {
            callback(data);
        },
        error: function (error) {
            let result = new ResultObject();
            if(error.getResponseHeader("authorizeuser") != undefined || error.getResponseHeader("authorizeuser") != null){
                if(error.getResponseHeader("authorizeuser") == "UnAuthorized"){
                    result.State = 403;
                }else{
                    result.State = 500;
                }
            }
            callback(result);
        }
    });
}

Happy Coding, Peace..

Comments

Post a Comment

Popular posts from this blog

Deploy Angular 8 app to Azure with Azure DevOps

Apache ActiveMQ 5 with .Net Core 3.1 and C#

Firebase with.Net Core and C#