0
votes

Trying to understand how JWT works for asp.net core application. I use a ASP.NET MVC Core application template. enter image description here

My StartUp.cs cotains configuration for JWT Token :

 public class Startup
{
     // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors();
        services.AddAuthentication(sharedOptions =>
        {
            sharedOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            sharedOptions.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            sharedOptions.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        }).AddJwtBearer(options =>
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = Configuration["Jwt:Issuer"],
                ValidAudience = Configuration["Jwt:Issuer"],
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
            };

            //options.EventsType = typeof(AuthenticateCustomEvent);
        });
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

        // In production, the React files will be served from this directory
        services.AddSpaStaticFiles(configuration =>
        {
            configuration.RootPath = "ClientApp/build";
        });
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseAuthentication();
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseSpaStaticFiles();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller}/{action=Index}/{id?}");
        });

        app.UseSpa(spa =>
        {
            spa.Options.SourcePath = "ClientApp";

            if (env.IsDevelopment())
            {
                spa.UseReactDevelopmentServer(npmScript: "start");
            }
        });
    }
}

And my login controller contains code to return token on successfull validation of the user this returns a token as shown below

enter image description here

Once i recieve the token i make a call to a controller with [Authorize] attribute applied to it with the bearer token from PostMan the controller never gets hit ? Am i missing something ?

1
I hope this answer may help you. stackoverflow.com/questions/52826970/… .you need to filter each desire api through ActionFilterAttribute(Middle Ware). - sebu
show the failing requiest&response as seen from postman - dee zg
Also decode your JWT token to confirm you set correct issue, audience . - Nan Yu

1 Answers

0
votes

My below solution is bit different, but this solution will help you to deal with custom auth implementation, you can implement a different type of auth for the different type of users. You require to create a class AuthorizationRequiredAttribute under your API project, this class will inherit ActionFilterAttribute class to filter each API request. you can filter all HTTP methods (GET, POST, PUT, DELETE...etc), and can implement your own authorization logic for specific HTTP method.

ActionFilterAttribute.cs

using BillSyatemCore.Common.Constants;
using BillSyatemCore.Services.Authentication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Net;
using System.Net.Http;

namespace BillSyatemCore.Handlers
{
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
    public class AuthorizationRequiredAttribute : ActionFilterAttribute
    {
        private IConfiguration _config;
        public AuthorizationRequiredAttribute(IConfiguration config)
        {
            _config = config;
        }
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            try
            {
                if (context.HttpContext.Request.Headers.ContainsKey(Constants.HttpHeaders.Token))
                {
                    var handler = new JwtSecurityTokenHandler();
                    var token = handler.ReadToken(context.HttpContext.Request.Headers[Constants.HttpHeaders.Token])
                        as JwtSecurityToken;
                    var expireDate = Convert.ToDateTime(token.Claims.First(claim => claim.Type == Constants.JwtClaims.ExpiresOn).Value);
                    if (context.HttpContext.Request.Method == WebRequestMethods.Http.Get)
                    {
                        if (expireDate < DateTime.Now)
                        {
                            context.Result = new UnauthorizedResult();
                        }
                    }
                    else
                    {

                        //You may filter post,put,delete etc request here.  
                    }
                }
                else
                {
                    context.Result = new NotFoundResult();
                }
            }
            catch (Exception ex)
            {
                context.Result = new BadRequestResult();
            }
            base.OnActionExecuting(context);
        }
    }
}

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    //JWT
    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = Configuration["Jwt:Issuer"],
            ValidAudience = Configuration["Jwt:Issuer"],
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
        };
    });
    services.AddCors(options =>
    {
        options.AddPolicy("CorsPolicy",
            builder => builder.AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowCredentials()
        .Build());
    });

}

Controller.cs

using BillSyatemCore.Models.Authentication;
using BillSystemCore.Transporter;
using Microsoft.AspNetCore.Mvc;

namespace TestProject.Controllers
{
    [Produces("application/json")]
    [Route("api/[controller]")]
    public class UserTypeController : Controller
    {
        private readonly IAuthTransporter _authTransporter;
        public UserTypeController(IAuthTransporter authTransporter)
        {
            _authTransporter = authTransporter;
        }
        [HttpPost("save"), ServiceFilter(typeof(AuthorizationRequiredAttribute))]
        public IActionResult Save([FromBody] UserType userType)
        {
            return Ok(_authTransporter.UserTypeServices.Save(userType));
        }
    }
}