0

I am stuck with an unusual problem.

I have the following:

  1. Web API Project using .net core
  2. Calling the API using Refit SDK.
  3. 3rd Calling those API's from the .Net core Razor Pages Front-end (Seperate Project.)

this is using the Jwt bearer token.

Below is the startup file code for API project.

services.AddMvc(options =>
                {
                    options.EnableEndpointRouting = false;
                    options.Filters.Add<ValidationFilter>();
                })
                .AddFluentValidation(mvcConfiguration => mvcConfiguration.RegisterValidatorsFromAssemblyContaining<Startup>())
                ;

            var jwtSettings = new JwtSettings();
            configuration.Bind(nameof(jwtSettings), jwtSettings);
            services.AddSingleton(jwtSettings);

            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwtSettings.Secret)),
                ValidateIssuer = false,
                ValidateAudience = false,
                RequireExpirationTime = false,
                ValidateLifetime = true
            };

            services.AddSingleton(tokenValidationParameters);

            services.AddAuthentication(x =>
                {
                    x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
                    x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                })
                .AddJwtBearer(x =>
                {
                    x.SaveToken = true;
                    x.TokenValidationParameters = tokenValidationParameters;
                });

            services.AddAuthorization(options =>
            {
                options.AddPolicy("MustWorkForChapsas", policy =>
                    {
                        policy.AddRequirements(new WorksForCompanyRequirement("chapsas.com"));
                    });
            });

            services.AddSingleton<IAuthorizationHandler, WorksForCompanyHandler>();

This is how i am using Authorize in my API Controllers.

 [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
    [ApiExplorerSettings(GroupName = "V1")]
    public class FaqsController : ControllerBase
    {
        protected readonly ILogger _logger;
        private readonly IFaqService _faqService;
        private readonly IMapper _mapper;
        private readonly IUriService _uriService;

This is how i ma generating my SKD using refit.

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using EdgeTours.API.Contracts.V1.Requests;
using EdgeTours.API.Contracts.V1.Requests.Queries;
using EdgeTours.API.Contracts.V1.Responses;
using EdgeTours.Model.CommonViewModels;
using Refit;

namespace EdgeTours.API.Sdk.V1
{
    [Headers("Authorization: Bearer")]
    public interface IFaqApi
    {
        [Get("/api/v1/faqs")]
        Task<ApiResponse<PagedResponse<FaqViewModel>>> GetAllAsync(string FaqId = null, int? PageNumber = 1, int? PageSize = 100);

Everything works fine and even i receive 401 error when i try to access that API from the browser with out bearer token.

enter image description here

The API works correctly from the Front-end Project.

Here's the code for startup file of the Front-end Project.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using EdgeTours.Repository.Context;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using System.Net;

namespace EdgeTours.Web
{
    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.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
            }
            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.UseStaticFiles();
            app.UseCookiePolicy();
            app.UseAuthentication();

            app.UseMvc();
        }
    }
}

The Problem:

I am unable to redirect to Login page as authorization is not enabled. I would really appreciate if you can help me to configure my razor pages class as well as startup file to enable authentication so that when API call is not valid I get redirected to my login page.

Kevin
  • 2,258
  • 1
  • 32
  • 40
  • Your API is okay, when someone is not authorized you want to send a 401 unauthorized rather than a redirect (depending on who consumes your API the redirect pages may be different). In your front end you want to check the response status, something like `if (response.StatusCode == HttpStatusCode.Unauthorized){//do redirect}` using a middleware to handle this might be your best choice. (you do this in the front end) – Kevin Nov 06 '19 at 08:09
  • https://stackoverflow.com/questions/10928277/redirect-to-another-page-when-user-is-not-authorized-in-asp-net-mvc3 this might also help you – Kevin Nov 06 '19 at 08:09
  • Thank you for the quick response. Can i use below lines in my Frontend .net core app startup file. – Shuja Haider Nov 06 '19 at 08:23
  • services.AddMvc().AddRazorPagesOptions(options => { options.Conventions.AuthorizePage("/Contact"); options.Conventions.AuthorizeFolder("/Private"); options.Conventions.AllowAnonymousToPage("/Private/PublicPage"); options.Conventions.AllowAnonymousToFolder("/Private/PublicPages"); }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2); – Shuja Haider Nov 06 '19 at 08:24
  • But when i add these lines. I start receiving below error. InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found. – Shuja Haider Nov 06 '19 at 08:36
  • unfortunately I am not familiar with frontend development using .net core and razor pages. Based on the error, I guess you will need to set an authentication scheme and default challenge scheme similar to how you have done in your backend – Kevin Nov 06 '19 at 09:04

0 Answers0