I made a CORS policy in my asp.net core API, but it seems the API is accessible for the public, as I can see the JSON by just typing the API URL in browser. So I just want my front-end(which is a angular app in the same host of API) have access to API not everyone.
this is my start up class:
public class Startup
{
readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
builder =>
{
builder.WithOrigins("myurl")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNamingPolicy = null;
options.JsonSerializerOptions.DictionaryKeyPolicy = null;
});
services.Configure<FormOptions>(o =>
{
o.ValueLengthLimit = int.MaxValue;
o.MultipartBodyLengthLimit = int.MaxValue;
o.MemoryBufferThreshold = int.MaxValue;
});
services.AddControllers();
string connectionString = "xxx";
services.AddDbContext<decorContext>(
option => option.UseSqlServer(connectionString)
);
}
// 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.UseDefaultFiles();
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory() ,#"StaticFiles")),
RequestPath = new PathString("/StaticFiles")
});
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
CORS is kicked in when Domain A accesses Domain B (like making an ajax call in js) and it won't apply when you hit the url directly. That's why it's called CROSS-ORIGIN.
You don't typically implement "script -> website" restriction. You could restrict access by location/IP, user identity/role/claims, or by checking if antiforgery token is present in a request. Check out Overview of ASP.NET Core Security
Related
I have designed my blazor wasm application and its hosted in blazor server app, therefore both applications share the same base url. When i launch my server app, it successfully launchers the wasm app. My problem is that when i hit the refresh button on the web browser , the api/server app loads in the browser instead of refreshing the blazor web assembly. How can i stop this?
This is my Server Startup class
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddControllersWithViews();
services.AddEndpointsApiExplorer();
services.AddSwaggerGen();
services.ConfigureCors();
services.ConfigureIISIntegration();
services.ConfigureLoggerService();
services.ConfigureMySqlContext(Configuration);
services.ConfigureRepositoryWrapper();
services.AddAutoMapper(typeof(Startup));
services.AddControllers();
services.AddRouting(options => options.LowercaseUrls = true);
}
// 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();
app.UseWebAssemblyDebugging();
}
else
{
app.UseHsts();
}
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseHttpsRedirection();
//app.UseCors("CorsPolicy");
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.All
});
app.UseRouting();
app.UseAuthorization();
app.UseMiddleware<ApiKeyMiddleware>();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapFallbackToFile("index.html");
});
}
}
My WASM Program.cs file
public class Program
{
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.Services.AddScoped(sp => new HttpClient(new AddHeadersDelegatingHandler())
{
BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
});
builder.Services.AddAntDesign();
builder.Services.Configure<ProSettings>(builder.Configuration.GetSection("ProSettings"));
builder.Services.AddScoped<IChartService, ChartService>();
builder.Services.AddScoped<IProjectService, ProjectService>();
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddScoped<IAccountService, AccountService>();
builder.Services.AddScoped<IProfileService, ProfileService>();
await builder.Build().RunAsync();
}
}
I am developing an asp.net core web api and I want to store a token that will be sent to my endpoints in order for a user to authenticate. For that I have some requirements which force me to implement an own authentication method. I inherit from AuthenticationHandler and implement the HandleAuthenticateAsync method:
public AuthenticateHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock,
IHttpContextAccessor httpContextAccessor)
: base(options, logger, encoder, clock)
{
AuthenticateHandlerHelperFunctions = new AuthenticateHandlerHelperFunctions();
_checkAccessTokenModel = new CheckAccessTokenModel();
session = httpContextAccessor.HttpContext.Session;
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
//before this: check header and get authorization informations
string submittedToken = authorizationheader.Substring("bearer".Length).Trim();
try
{
if (string.IsNullOrEmpty(session.GetString("Token")))
{
_checkAccessTokenModel = await AuthenticateHandlerHelperFunctions.CheckAccessToken(submittedToken);
if(_checkAccessTokenModel.Active == false)
{
_failReason = "Token not valid anymore, request another one!";
return AuthenticateResult.Fail("Token not valid anymore, request another one!");
}
session.SetString("Token", submittedToken);
}
}
catch
{
return AuthenticateResult.Fail("Invalid Authorization Header");
}
var claims = new[] {
new Claim(ClaimTypes.Name, _checkAccessTokenModel.Exp.ToString()),
};
var identity = new ClaimsIdentity(claims, Scheme.Name);
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, Scheme.Name);
return AuthenticateResult.Success(ticket);
}
The goal is to use the session to save the token and not execute the CheckAccessToken method for every request. I will get frequent data on the endpoints that are configured with [Authorize] so I want to save computing time. I looked this up and most of the errors where problems with the startup where the app.UseSession() was not set correctly etc. but not in my case I believe. Here is my Startup:
public void ConfigureServices(IServiceCollection services)
{
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "DigVPapi", Version = "v1" });
});
services.AddDbContextFactory<AntragDBNoInheritanceContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
});
services.AddAuthentication("BasicAuthentication")
.AddScheme<AuthenticationSchemeOptions, AuthenticateHandler>("BasicAuthentication", null);
services.AddDistributedMemoryCache();
services.AddSession(options =>
{
options.IdleTimeout = System.TimeSpan.FromSeconds(10);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
});
services.AddHttpContextAccessor();
services.AddSingleton<IJWTManagerRepository, JWTManagerRepository>();
services.AddControllers();
}
// 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", "DigVPapi v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
If this is not possible. What could I do instead to save the token in some different way? Of course I could save the token in the database but this would only move the problem to a database query tha twould be made every time. The error that I get when trying to authenticate is following
System.InvalidOperationException: 'Session has not been configured for this application or request.'
I have a blazor wasm hosted solution that is setup using Role authentication. However, whenever I add an [Authorize] attribute to any of my API Controllers I get a 401 Unauthorized. I know the user has the proper role as the UI is showing and hiding features for that role. Its like the roles are not being passed up to the API. What am I missing?
Server - Starup.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.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
//Register the Datacontext and Connection String
services.AddDbContext<DataContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDatabaseDeveloperPageExceptionFilter();
//Sets up the default Asp.net core Identity Screens - Use Identity Scaffolding to override defaults
services.AddDefaultIdentity<ApplicationUser>( options =>
{
options.SignIn.RequireConfirmedAccount = true;
options.Password.RequireDigit = true;
options.Password.RequireLowercase = true;
options.Password.RequireUppercase = true;
options.Password.RequiredUniqueChars = 0;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequiredLength = 8;
options.User.RequireUniqueEmail = true;
})
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<DataContext>();
//Associates the User to Context with Identity
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, DataContext>( options =>
{
options.IdentityResources["openid"].UserClaims.Add(JwtClaimTypes.Role);
options.ApiResources.Single().UserClaims.Add(JwtClaimTypes.Role);
});
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove(JwtClaimTypes.Role);
//Adds authentication handler
services.AddAuthentication().AddIdentityServerJwt();
//Register Repositories for Dependency Injection
services.AddScoped<ICountryRepository, CountryRepository>();
services.AddControllersWithViews();
services.AddRazorPages();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, DataContext dataContext)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseMigrationsEndPoint();
app.UseWebAssemblyDebugging();
}
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();
}
//AutoMigrates data
dataContext.Database.Migrate();
app.UseHttpsRedirection();
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseSerilogIngestion();
app.UseSerilogRequestLogging();
app.UseRouting();
app.UseIdentityServer();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapFallbackToFile("index.html");
});
}
}
Client - Program.cs
public class Program
{
public static async Task Main(string[] args)
{
//Serilog
var levelSwitch = new LoggingLevelSwitch();
Log.Logger = new LoggerConfiguration()
.MinimumLevel.ControlledBy(levelSwitch)
.Enrich.WithProperty("InstanceId", Guid.NewGuid().ToString("n"))
.WriteTo.BrowserHttp(controlLevelSwitch: levelSwitch)
.CreateLogger();
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.Services.AddHttpClient("XXX.ServerAPI", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
// Supply HttpClient instances that include access tokens when making requests to the server project
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("XXX.ServerAPI"));
builder.Services.AddApiAuthorization()
.AddAccountClaimsPrincipalFactory<RolesClaimsPrincipalFactory>();
var baseAddress = new Uri($"{builder.HostEnvironment.BaseAddress}api/");
void RegisterTypedClient<TClient, TImplementation>(Uri apiBaseUrl)
where TClient : class where TImplementation : class, TClient
{
builder.Services.AddHttpClient<TClient, TImplementation>(client =>
{
client.BaseAddress = apiBaseUrl;
});
}
RegisterTypedClient<ICountryService, CountryService>(baseAddress);
await builder.Build().RunAsync();
}
}
RolesClaimPrincipalFactory.cs
public class RolesClaimsPrincipalFactory : AccountClaimsPrincipalFactory<RemoteUserAccount>
{
public RolesClaimsPrincipalFactory(IAccessTokenProviderAccessor accessor) : base(accessor)
{
}
public async override ValueTask<ClaimsPrincipal> CreateUserAsync(
RemoteUserAccount account,
RemoteAuthenticationUserOptions options)
{
ClaimsPrincipal user = await base.CreateUserAsync(account, options);
if (user.Identity.IsAuthenticated)
{
var identity = (ClaimsIdentity)user.Identity;
Claim[] roleClaims = identity.FindAll(identity.RoleClaimType).ToArray();
if (roleClaims != null && roleClaims.Any())
{
foreach (Claim existingClaim in roleClaims)
{
identity.RemoveClaim(existingClaim);
}
var rolesElem = account.AdditionalProperties[identity.RoleClaimType];
if (rolesElem is JsonElement roles)
{
if (roles.ValueKind == JsonValueKind.Array)
{
foreach (JsonElement role in roles.EnumerateArray())
{
identity.AddClaim(new Claim(options.RoleClaim, role.GetString()));
}
}
else
{
identity.AddClaim(new Claim(options.RoleClaim, roles.GetString()));
}
}
}
}
return user;
}
}
You are likely having this issue since you are using ICountryService that has it's own http client which is not configured to include auth tokens in the outgoing requests -- no tokens, no access.
We can attach tokens by adding an AuthorizationMessageHandler to the client, just like your named client (XXX.ServerAPI) is configured.
Try changing your typed client helper method to this:
/* Client Program.cs */
void RegisterTypedClient<TClient, TImplementation>(Uri apiBaseUrl)
where TClient : class where TImplementation : class, TClient
{
builder.Services.AddHttpClient<TClient, TImplementation>(
client => client.BaseAddress = apiBaseUrl)
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
}
You probably want to change the helper to also only include tokens to client's that actually require them (if you are using that helper for other clients as well)
See the docs for more info.
I've got a site using the new dotnetcore3 angular template. I've created a custom authorization filter that's currently extremely simple
public class ClaimRequirementFilter : IAuthorizationFilter
{
readonly string _claim;
public ClaimRequirementFilter(string claim)
{
_claim = claim;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
if (_claim != "test")
{
context.Result = new ForbidResult();
}
}
}
public class ClaimRequirementAttribute : TypeFilterAttribute
{
public ClaimRequirementAttribute(string claimType) : base(typeof(ClaimRequirementFilter))
{
Arguments = new object[] {claimType };
}
}
[Route("{jobId}")]
[ClaimRequirement("testfail")]
[HttpGet]
public async Task<IActionResult> GetJob([FromRoute] Guid jobId)
{
//stuff
{
However, whenever a request fails (which will be all of them right now), it 302s me to the AccessDenied page with a returnUrl of the URL I was trying to hit.
However, since this request is being made from my angular client, I would rather it just return a 401 (or 403 since in this case it's because the loggedin user doesn't have permission to do what they're trying to do), and I'm not sure how to configure it.
Per Ruard's request, here is my Startup configuration
public class Startup
{
public Startup(IWebHostEnvironment env, IConfiguration configuration)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
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.AddApplicationInsightsTelemetry();
services.AddDbContext<ApplicationDbContext>(
options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))
);
services.AddTransient<EmailSender, EmailSender>();
services.AddScoped<IRazorViewToStringRenderer, RazorViewToStringRenderer>();
services.Configure<EmailServiceConfiguration>(Configuration.GetSection("EmailServiceConfiguration"));
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddDefaultTokenProviders()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer(options =>
{
options.UserInteraction.LoginUrl = "/auth/login";
options.UserInteraction.LogoutUrl = "/auth/logout";
})
//.AddDeveloperSigningCredential()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services.AddAuthentication()
// .AddGoogle(options =>
// {
// IConfigurationSection googleAuthNSection = Configuration.GetSection("Authentication:Google");
// options.ClientId = googleAuthNSection["ClientId"];
// options.ClientSecret = googleAuthNSection["ClientSecret"];
// })
.AddIdentityServerJwt();
services.AddControllersWithViews().AddRazorRuntimeCompilation();
services.AddRazorPages(options =>
{
options.Conventions.AddAreaPageRoute("Identity", "/Identity/Account/Login", "/auth/login");
});
services.AddAuthorization(options =>
{
// options.AddPolicy("RequireAdmin", policy =>
// {
// policy.RequireRole("Admin");
// });
// options.AddPolicy("CreateInternalUsers", policy =>
// {
// // policy.RequireRole("Admin");
// policy.RequireClaim("CreatePPGUser");
// });
});
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
services.AddControllers()
.AddNewtonsoftJson(options =>
{
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ApplicationDbContext context, IServiceProvider services)
{
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();
}
context.Database.Migrate();
app.UseHttpsRedirection();
app.UseStaticFiles();
if (!env.IsDevelopment())
{
app.UseSpaStaticFiles();
}
app.UseRouting();
app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}"
);
endpoints.MapRazorPages();
});
app.UseSpa(spa =>
{
// To learn more about options for serving an Angular SPA from ASP.NET Core,
// see https://go.microsoft.com/fwlink/?linkid=864501
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
// spa.UseAngularCliServer(npmScript: "start");
spa.UseProxyToSpaDevelopmentServer("http://localhost:4200");
}
});
CreateUserRoles(services).Wait();
}
}
You should add a controller that serves as api. From the documentation:
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
Methods from this controller will return the StatusCode instead of redirecting the user to a view.
Update
Based on your startup, it seems that you are not setting the CompatibilityVersion:
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
As documented, this is required in combination with ApiController:
The preceding change:
Is required to use the [ApiController] attribute at the controller level.
Opts in to potentially breaking behaviors introduced in ASP.NET Core 2.2.
In your case, assuming version 3.0:
services.AddControllers()
.AddNewtonsoftJson(options =>
{
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
})
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
Good Day,
I'm stumped as to why even though I use the [Authorize] attribute on my controllers, it doesn't check to see if a user is logged in and still passes as an Authorization success. I am following the basic Identity and Authorization tutorials from Microsoft, HERE and HERE. I was able to get basic authentication up, creating a user and logging in and all that, but the authorization just allows guest to pass through and the system falsely recognizes them as successful. I used chrome to test, so i even used private mode and cleared the cookies and cache in the event the information was stored. I'm completely stumped, and I don't know what else to do.
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService: Information: Authorization was successful.
Is the Authorization success message I get in the Debug console log.
Below is 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.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.AddRazorPages();
services.AddControllersWithViews();
services.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
});
services.AddDbContext<DevContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddDbContext<UserContext>(options => options.UseSqlServer(Configuration.GetConnectionString("UserContextConnection")));
services.AddIdentity<User, IdentityRole>().AddEntityFrameworkStores<UserContext>().AddDefaultTokenProviders();
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.ConfigureApplicationCookie(options =>
{
//Cokie Settings
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromDays(150);
//If the LoginPath isn't set, ASP.NET Core defaults the path to Account/Login.
// options.LoginPath = "/Account/Login";
// options.AccessDeniedPath = "/Account/AccessDenied";
options.LoginPath = $"/Identity/Account/Login";
options.LogoutPath = $"/Identity/Account/Logout";
options.AccessDeniedPath = $"/Identity/Account/AccessDenied";
options.SlidingExpiration = true;
});
// services.AddSingleton<IEmailSender, EmailSender> ();
}
// 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.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
endpoints.MapDefaultControllerRoute().RequireAuthorization();
}
);
}
}
Below is the User.cs, left it blank because the basic demo didn't have any custom fields and it still worked. So I wasn't sure that would be the issue.
public class User : IdentityUser
{
}
And this is the Home Controller with the [Authorize] attributes
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
[Authorize]
public IActionResult Information()
{
ViewData["Message"] = "Test Information Page";
return View();
}
[Authorize]
public IActionResult About()
{
ViewData["Message"] = "Your application description page.";
return View();
}
[Authorize]
public IActionResult Contact()
{
ViewData["Message"] = "Your contact page.";
return View();
}
[Authorize]
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
I think your problem is this line:
services.AddAuthentication(IISDefaults.AuthenticationScheme);
This means your application will use your windows login to authenticate you and not the cookie you created.
I would change it to this since you are using a cookie based authentication scheme:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie();
See guide below:
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/cookie?view=aspnetcore-3.0
I would also add functionality for creating and handling an antiforgery token to secure your application against cross-forgery.
Update (Solution):
This implementation is usign Identity which is already added so no need to call AddAuthentication()
Similar issue to this: github.com/aspnet/AspNetCore/issues/4656