Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JWT Authentication ASP.NET Core MVC application

I've seen numerous examples of how to use JWT authentication with Angular, React, Vue etc... clients but can't find any examples of using JWT authentication with ASP.NET Core (specifically 2.2) Web App Mvc.

Does anyone have any examples or advice on how to do this?

Thanks,

like image 871
user5413800 Avatar asked Feb 14 '26 14:02

user5413800


2 Answers

You can use this class based on nuget package JWT 3.0.3

using JWT;
using JWT.Algorithms;
using JWT.Serializers;
using Newtonsoft.Json;
using System;

namespace Common.Utils
{
  public class JwtToken
  {
    private IJwtEncoder encoder;
    private IJwtDecoder decoder;

    /// <remarks>
    /// This requires a key value randomly generated and stored in your configuration settings. 
    /// Consider that it is a good practice use keys as at least long as the output digest bytes 
    /// length produced by the hashing algorithm used. Since we use an HMAC-SHA-512 algorithm, 
    /// then we can provide it a key at least 64 bytes long.
    /// <see cref="https://tools.ietf.org/html/rfc4868#page-7"/>
    /// </remarks>
    public string SecretKey { get; set; } 

    public JwtToken()
    {
        IJwtAlgorithm algorithm = new HMACSHA512Algorithm();
        IJsonSerializer serializer = new JsonNetSerializer();
        IDateTimeProvider datetimeProvider = new UtcDateTimeProvider();
        IJwtValidator validator = new JwtValidator(serializer, datetimeProvider);
        IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();

        encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
        decoder = new JwtDecoder(serializer, validator, urlEncoder);
        SecretKey = "";
    }

    public JwtToken(string secretKey) : this()
    {
        SecretKey = secretKey;
    }

    public bool IsTokenValid(string token)
    {
        return !string.IsNullOrWhiteSpace(DecodeToken(token));
    }

    public string GetToken(object payload)
    {
        try
        {
            return encoder.Encode(payload, SecretKey);
        }
        catch (Exception)
        {
            return encoder.Encode(new DataModel(payload), SecretKey);
        }
    }

    public string DecodeToken(string token)
    {
        try
        {
            if (string.IsNullOrWhiteSpace(token) || token == "null")
            {
                return null;
            }
            return decoder.Decode(token, SecretKey, true);
        }
        catch (TokenExpiredException)
        {
            return null;
        }
        catch (SignatureVerificationException)
        {
            return null;
        }
    }

    public T DecodeToken<T>(string token) where T : class
    {
        try
        {
            if (string.IsNullOrWhiteSpace(token))
            {
                return null;
            }
            return decoder.DecodeToObject<T>(token, SecretKey, true);
        }
        catch (TokenExpiredException)
        {
            return null;
        }
        catch (SignatureVerificationException)
        {
            return null;
        }
        catch (Exception)
        {
            var data = decoder.DecodeToObject<DataModel>(token, SecretKey, true).Data;
            return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(data));
        }
    }
  }

  public class DataModel
  {
    public DataModel(object data)
    {
        Data = data;
    }
    public object Data { get; set; }
  }
}

Then in your Startup class Configure method set the jwt middleware for check authentication status of each request:

app.Use((context, next) =>
        {

            // verify app access token if not another service call
            var appAccessToken = context.Request.Headers["Authorization"];
            if (appAccessToken.Count == 0)
            {
                context.Items["User"] = null;
            }
            else
            {
                var token = appAccessToken.ToString().Replace("Bearer ", "");
                var jwtToken = new JwtToken(config.JwtTokenSecret); //you need a secret (with requirements specified above) in your configuration (db, appsettings.json)
                if (string.IsNullOrWhiteSpace(token) || !jwtToken.IsTokenValid(token))
                {
                    context.Response.StatusCode = 401;
                    return Task.FromResult(0);
                }

                dynamic user = jwtToken.DecodeToken<dynamic>(token);

                var cachedToken = cache.Get(user.Id);  //you need some cache for store your token after login success and so can check against
                if (cachedToken == null || cachedToken.ToString() != token)
                {
                    context.Response.StatusCode = 401;
                    return Task.FromResult(0);
                }

                context.Items["User"] = new Dictionary<string, string>() {
                        { "FullName",user.Name?.ToString()},
                        { "FirstName",user.FirstName?.ToString()},
                        { "LastName",user.LastName?.ToString()},
                        { "Role",user.Role?.ToString()},
                        { "Email",user.Email?.ToString()}
                    };
            }
            return next();
        });

And finally you need generate the token and return it after authentication:

    [AllowAnonymous]
    public IActionResult Login(string username, string password)
    {
        User user = null; //you need some User class with the structure of the previous dictionary
        if (checkAuthenticationOK(username, password, out user)) //chackAuthenticationOk sets the user against db data after a succesfull authentication
        {
           var token = new JwtToken(_config.JwtTokenSecret).GetToken(user);  //_config is an object to your configuration
           _cache.Set(user.id, token);  //store in the cache the token for checking in each request
           return Ok(token);
        }

        return StatusCode(401, "User is not authorized");
    }
like image 146
Ciro Corvino Avatar answered Feb 17 '26 10:02

Ciro Corvino


Add following code to startup

public void ConfigureServices(IServiceCollection services)
    {

        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer = true,
                    ValidateAudience = true,
                    ValidateLifetime = true,
                    ValidateIssuerSigningKey = true,
                    ValidIssuer = Configuration["Issuer"],
                    ValidAudience = Configuration["Audience"],
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["SigningKey"]))
                };
            });

    }


 public void Configure(IApplicationBuilder app, IHostingEnvironment env,, ILoggerFactory loggerFactory)
  {
   app.UseAuthentication();

}

Code for login action in AccountController

[Route("api/[controller]")]
public class AccountController : Controller
{
[AllowAnonymous]
[HttpPost]
[Route("login")]
public IActionResult Login([FromBody]LoginViewModel loginViewModel)
{

    if (ModelState.IsValid)
    {
        var user = _userService.Authenticate(loginViewModel);


        var claims = new[]
        {
                new Claim(JwtRegisteredClaimNames.Sub, loginViewModel.Username),
                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
                };

        var token = new JwtSecurityToken
                    (
                        issuer: _configuration["Issuer"],
                        audience: _configuration["Audience"],
                        claims: claims,
                        expires: DateTime.UtcNow.AddDays(10),
                        notBefore: DateTime.UtcNow,
                        signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["SigningKey"])),
                             SecurityAlgorithms.HmacSha256)
                    );

        return Ok(new
        {
            access_token = new JwtSecurityTokenHandler().WriteToken(token),
            expires_in = (int)token.ValidTo.Subtract(DateTime.UtcNow).TotalSeconds,// TimeSpan.FromTicks( token.ValidTo.Ticks).TotalSeconds,
            sub = loginViewModel.Username,
            name = loginViewModel.Username,
            fullName = user.FullName,
            jobtitle = string.Empty,
            phone = string.Empty,
            email = user.EmailName,

        });
    }
}

}
like image 31
Ehasanul Hoque Avatar answered Feb 17 '26 10:02

Ehasanul Hoque



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!