Skip to main content

JWT Authentication (ASP.NET Core + Angular) - Backend


 Key code Snippet are followings

Back End:

Startup.cs

    public class Startup

    {

        public Startup(IConfiguration configuration)

        {

            Configuration = configuration;

        }


        public IConfiguration Configuration { get; }


        // This method gets called by the runtime. Use this method to add services to the container.

        public void ConfigureServices(IServiceCollection services)

        {

            services.AddDbContext<PharmaDbContext>(options =>

                        options.UseSqlServer(Configuration.GetConnectionString("DBConnection")));


            services.AddControllers();

            services.AddSwaggerGen(c =>

            {

                c.SwaggerDoc("v1", new OpenApiInfo { Title = "PharmaSuite", Version = "v1" });

            });


            services.ConfigureMappings();

            services.ConfigureBusinessServices(Configuration);

            services.ConfigureRepositories(Configuration);

            services.AddCors();

            services.AddHttpContextAccessor();


            // Configure Authentication


            var jwtSettings = Configuration.GetSection("JWTSettings")

                                                     .Get<JWTSettings>();


            services.AddAuthentication(auth =>

            {

                auth.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;

                auth.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;

            })

            .AddJwtBearer(options =>

            {

                options.SaveToken = true;

                options.TokenValidationParameters = new TokenValidationParameters

                {

                    ValidateIssuer = true,

                    ValidIssuer = jwtSettings.Issuer,

                    ValidateAudience = true,

                    ValidAudience = jwtSettings.Audience,

                    ValidateIssuerSigningKey = true,

                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.Secret))

                };

            });



        }


        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

        {

            if (env.IsDevelopment())

            {

                app.UseDeveloperExceptionPage();

                app.UseSwagger();

                app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "PharmaSuite v1"));

            }


           


            app.UseHttpsRedirection();


            app.UseRouting();


            // global cors policy

            app.UseCors(x => x

                .AllowAnyMethod()

                .AllowAnyHeader()

                .SetIsOriginAllowed(origin => true) // allow any origin

                .AllowCredentials()); // allow credentials


            HttpContextHelper.Configure(app.ApplicationServices.GetRequiredService<IHttpContextAccessor>());


            app.UseAuthentication();

            app.UseAuthorization();


            app.UseEndpoints(endpoints =>

            {

                endpoints.MapControllers();

            });



        }

    }

}


.csproj: Nuget  package for JWT
    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.6" />
    <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.7.1" />


namespace PharmaSuite.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class AccountController : BaseController
    {
        private readonly IUserService _userService;
        private readonly IConfiguration _configuration;
        public AccountController(IUserService userService, IConfiguration configuration)
        {
            _userService = userService;
            _configuration = configuration;
        }

        [AllowAnonymous]
        [HttpPost]
        [Route("Authenticate")]
        public async Task<IActionResult> Authenticate(UserLogin userLogin)
        {
            var candidate = await _userService.AuthenticateUser(userLogin);

            if (candidate != null)
            {
                var loginUser = await _userService.GetUserAsync(candidate.Id);

                var claims = new List<Claim>();
                claims.Add(new Claim("UserName", loginUser.UserName));
                claims.Add(new Claim("Email", loginUser.Email));
                claims.Add(new Claim("UserType", loginUser.UserType));
                claims.Add(new Claim("CompanyId", loginUser.CompanyId.ToString()));
                claims.Add(new Claim("UserId", loginUser.Id.ToString()));

                // Add roles as multiple claims
                foreach (var role in loginUser.Roles)
                {
                    claims.Add(new Claim(ClaimTypes.Role, role.Name));
                }

                var jwtSettings = _configuration.GetSection("JWTSettings")
                                         .Get<JWTSettings>();

                var token = JwtHelper.GetJwtToken(
                                loginUser.UserName,
                                jwtSettings.Secret,
                                jwtSettings.Issuer,
                                jwtSettings.Audience,
                                TimeSpan.FromMinutes(jwtSettings.TokenTimeoutMinutes),
                                claims.ToArray());

                var response = new TokenResponse()
                {
                    AccessToken = new JwtSecurityTokenHandler().WriteToken(token),
                    ExpiresOnUtc = token.ValidTo,
                    RoutePermissions = loginUser.RoutePermissions
                };

                return Ok(response);
            }
            else
            {
                return Unauthorized("Invalid Login Credentials!");
            }
        }

    }
}


TokenResponse Model:
public class TokenResponse
    {
        public string AccessToken { get; set; }
        public DateTime ExpiresOnUtc { get; set; }
        public List<UserRoutePermission> RoutePermissions { get; set; }
    }

JwtHelper : 

namespace PharmaSuite.Common.Helpers
{
    public class JwtHelper
    {
        public static JwtSecurityToken GetJwtToken(
        string username,
        string signingKey,
        string issuer,
        string audience,
        TimeSpan expiration,
        Claim[] additionalClaims = null)
        {
            var claims = new[]
            {
            new Claim(JwtRegisteredClaimNames.Sub,username),
            // this guarantees the token is unique
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
        };

            if (additionalClaims is object)
            {
                var claimList = new List<Claim>(claims);
                claimList.AddRange(additionalClaims);
                claims = claimList.ToArray();
            }

            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(signingKey));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

            return new JwtSecurityToken(
                issuer: issuer,
                audience: audience,
                expires: DateTime.UtcNow.Add(expiration),
                claims: claims,
                signingCredentials: creds
            );
        }
    }
}

HttpContextHelper:

namespace PharmaSuite.Common.Helpers
{
    public static class HttpContextHelper
    {
        private static IHttpContextAccessor _httpContextAccessor;

        public static void Configure(IHttpContextAccessor httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor;
        }

        public static HttpContext HttpContext => _httpContextAccessor.HttpContext;
    }
}


BaseController:
namespace PharmaSuite.Controllers
{
    [ApiController]
    public class BaseController : ControllerBase
    {
       public CurrentUser CurrentUser { get { return this.currentUser; } }
       private CurrentUser currentUser = null;

        public BaseController()
        {
            
                var identity = HttpContextHelper.HttpContext.User.Identity as ClaimsIdentity;

                if (identity != null && identity.Claims != null && identity.Claims.Any())
                {
                    currentUser = new CurrentUser();

                    currentUser.UserId = Convert.ToInt32(identity.FindFirst("UserId").Value);
                    currentUser.CompanyId = Convert.ToInt32(identity.FindFirst("CompanyId").Value);
                    currentUser.UserType = identity.FindFirst("UserType").Value;
                    currentUser.UserName = identity.FindFirst("UserName").Value;
                    currentUser.Email = identity.FindFirst("Email").Value;
                }

        }
    }
}

Comments

Popular posts from this blog

Cannot access a disposed object. A common cause of this error is disposing a context that was

  Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances. Object name: 'PropertyContext'.  public class CustomerHub : Hub     {         public readonly ICustomerService _customerService;         private readonly IServiceScopeFactory _serviceScopeFactory;         public CustomerHub(ICustomerService service, IServiceScopeFactory serviceScopeFactory)         {             _customerService = service;             _serviceScopeFactory = serviceSco...

Limit Upload File Type Extensions ASP.NET MVC 5

  //-----------------------------------------------------------------------    // <copyright file="AllowExtensionsAttribute.cs" company="None">    //     Copyright (c) Allow to distribute this code and utilize this code for personal or commercial purpose.    // </copyright>    // <author>Asma Khalid</author>    //-----------------------------------------------------------------------       namespace  ImgExtLimit.Helper_Code.Common   {        using  System;        using  System.Collections.Generic;        using  System.ComponentModel.DataAnnotations;        using  System.Linq;      ...