mohammed besher
mohammed besher

Reputation: 378

Getting 404 error instead of 401, when token is expired or when token is not passed Asp.net core 2

I created Asp.net-core 2 project and added

  1. api controller authorized by Bearer token.
  2. mvc controllers authorized by CookieAuthenticationDefaults.AuthenticationScheme.
  3. don't have app.UseIdentity(); in Configure functions

When I tried to call API published in IIS express, it will returned 401 unauthorized.

When I tried to call API published in IIS, it will returned 404 not found.

I am getting 404 error instead of 401, when token is expired or when token is not passed.

and my startup:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApiContext>();
        //options =>
        //    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
        services.AddTransient<ApiContextSeed>();
        //a confirmed email.
        services.AddIdentity<ApplicationUser, IdentityRole>(config =>
        {
            config.SignIn.RequireConfirmedEmail = true;
            config.Password.RequireDigit = false;
            config.Password.RequireLowercase = false;
            config.Password.RequireNonAlphanumeric = false;
            config.Password.RequireUppercase = false;
            config.Password.RequiredUniqueChars =0;
            config.Password.RequiredLength = 6;
            config.User.AllowedUserNameCharacters = null;
          
        })
            .AddEntityFrameworkStores<ApiContext>()
            .AddDefaultTokenProviders();

        // Add application services.
        services.AddTransient<IEmailSender, EmailSender>();
        services.AddMvc().AddSessionStateTempDataProvider();
        services.AddResponseCaching();
        services.AddAutoMapper();
        services.AddSingleton<IEmailSender, EmailSender>();
        services.AddSingleton<IWizIQSender, WizIQSender>();
        services.AddSingleton<IWizIQClass, WizIQClass>();
        services.AddSingleton<ITimeZone, TimeZone>();
        services.AddSingleton<IPinCodeGenerator, PinCodeGenerator>();
        services.AddScoped<IUnitOfWorkAsync, UnitOfWorkAsync>();
        services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
        services.AddBootstrapPagerGenerator(options =>
        {
            // Use default pager options.
            options.ConfigureDefault();
        });         
        services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
             
              .AddCookie("UserAuth", options =>
        {
           
            options.LoginPath = string.Empty;



        });      
        services.AddDistributedMemoryCache();         
        #region FlashMessage

        services.AddSession();
        // Needed so we can access the user's session.
        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        services.AddScoped(x => x.GetRequiredService<IHttpContextAccessor>().HttpContext.Session);

        services.AddScoped<IMessageProvider, SessionMessageProvider>();

        // Customize the message types (i.e. we are using Bootstrap v3 and need to provide a custom-value for the error message-type).
        services.AddScoped<IMessageTypes>(x =>
        {
            return new MessageTypes(error: "danger");
        });

        services.AddScoped<IMessengerOptions, MessengerOptions>();

        // We are using a stack to hold messages (i.e. LIFO).
        services.AddScoped<IMessenger, StackMessenger>();

        #endregion
        services.AddCors(cfg =>
        {
            cfg.AddPolicy("UserPanel", bldr =>
            {
                bldr.AllowAnyHeader()
                    .AllowAnyMethod()
                .AllowAnyOrigin();
            });
        });
        //using JWT
        services.AddAuthentication()
              .AddJwtBearer(cfg =>
              {
                  cfg.RequireHttpsMetadata = false;
                  cfg.SaveToken = true;
                  cfg.TokenValidationParameters = new TokenValidationParameters()
                  {
                      ValidIssuer = Configuration["Tokens:Issuer"],
                      ValidAudience = Configuration["Tokens:Issuer"],  
                      IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Tokens:Key"]))
                  };

              });


        services.AddMvc();
        services.AddSingleton<IEmailSender, EmailSender>();
        //services.AddUrlHelper();
        services.AddTransient<IEmailSender, EmailSender>();

        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new Info { Title = "Drossey API", Version = "v1" });
        });


    } 

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ApiContextSeed seeding)
   {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseBrowserLink();
            app.UseDatabaseErrorPage();
        }
        else
        {
             app.UseExceptionHandler("/error");
            app.UseStatusCodePagesWithReExecute("/error");

        }
        app.UseStaticFiles();       
        app.UseSession();
        app.UseAuthentication();
        app.UseCors("UserPanel");
        app.UseSwagger();
        app.UseSwaggerUI(c =>
        {
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "Drossey Api");
        });
        app.UseMvc(routes =>
        {            
            routes.MapRoute(
            name: "areaRoute",
            template: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
      
            routes.MapRoute(
              name: "default",
              template: "{controller=Home}/{action=Index}/{id?}");
        });           
        seeding.EnsureSeeding().Wait();
    }

and this my API controller:

public class CodeController : BaseController
{
    private readonly IPinCodeGenerator _pinCodeGenerator;

    public CodeController(IUnitOfWorkAsync unitOfWork,
        UserManager<ApplicationUser> userMgr, IPasswordHasher<ApplicationUser> hasher, 
        ILogger<AuthController> logger, IConfiguration config, IMapper mapper, IPinCodeGenerator pinCodeGenerator) :
        base(unitOfWork, userMgr, hasher, logger, config, mapper)
    {
        _pinCodeGenerator = pinCodeGenerator;
    }
    
    [HttpPost]
    public async Task<IActionResult> Add([FromBody]CodeAddViewModel model)
    {

        try
        {
            if (ModelState.IsValid)
            {
                var userId = await GetUserId();
                var user = await _userMgr.FindByIdAsync(userId);

                var random = Convert.ToDouble(model.Code.Substring(0, 10));
                var code = model.Code.Substring(10, 5);
                var pinCode = _unitOfWork.PinCodeRepository.Filter(u => u.Code == random).FirstOrDefault();
                if (pinCode == null || pinCode.Status != CodeStatus.IsActive)
                {
                    return StatusCode(400, "InValidCode");
                }
                else
                {
                    string codeStr = _pinCodeGenerator.GetCode(pinCode.Amount, pinCode.Code,
                        pinCode.Vector, pinCode.Key);
                    if (codeStr != model.Code)
                    {
                        return StatusCode(400, "InValidCode");
                    }
                    else
                    {
                        user.Balance += pinCode.Amount;
                        await _userMgr.UpdateAsync(user);
                        pinCode.Status = CodeStatus.Shipped;
                        await _unitOfWork.CommitAsync();
                        return Ok();

                    }
                }

            }
            return StatusCode(400, ModelState);
        }
        catch (Exception e)
        {

            return StatusCode(500, e.Message);
        }
       
        

    }
}

and base controller contains

 public class BaseController : Controller
{
    public readonly ILogger<AuthController> _logger;
    public readonly SignInManager<ApplicationUser> _signInMgr;
    public readonly UserManager<ApplicationUser> _userMgr;
    public readonly IPasswordHasher<ApplicationUser> _hasher;
    public readonly IConfiguration _config;
    public IUnitOfWorkAsync _unitOfWork;
    protected readonly IMapper _mapper;

    public BaseController(IUnitOfWorkAsync unitOfWork,
       
        UserManager<ApplicationUser> userMgr,
        IPasswordHasher<ApplicationUser> hasher,
        ILogger<AuthController> logger,
        IConfiguration config,
        IMapper mapper
        )
    {
        _unitOfWork = unitOfWork;
        //_signInMgr = signInMgr;
        _logger = logger;
        _userMgr = userMgr;
        _hasher = hasher;
        _config = config;
        _mapper = mapper;


    }

    protected async Task<string> GetUserId()
    {
        try
        {
            var userName = this.User.FindFirst(ClaimTypes.NameIdentifier).Value;
            if (!string.IsNullOrEmpty(userName))
            {
                var user = await _userMgr.FindByNameAsync(userName);
                if (user != null)
                    return user.Id;
                else
                    return null;
            }
        }
        catch (Exception)
        {

            return null;
        }

        return null;
    }

}

Upvotes: 3

Views: 2037

Answers (2)

Ayantha
Ayantha

Reputation: 1

Change [Authorize] to [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

Upvotes: 0

mohammed besher
mohammed besher

Reputation: 378

app.UseStatusCodePagesWithReExecute("/error") in startup.cs hide 401 un Authorized error .

Upvotes: 6

Related Questions