Migrating from asp net 2.2 to 3.1 Authorization Issue - asp.net-core

I have an issue with authentication and authorization when I migrated my web app from asp 2.2 to 3.1.
looks OK and behaves as normal with CRUD operations and other things.
In my SignIn.cshtml.cs file I have this:
public async Task<IActionResult> OnPostAsync()
{
if (ModelState.IsValid)
{
var result = await signinManager.PasswordSignInAsync
(SignInData.UserName, SignInData.Password,
SignInData.RememberMe, false);
if (result.Succeeded)
{
return RedirectToPage("../StartPage");
}
else
{
ModelState.AddModelError("", "Invalid login!");
}
}
return Page();
}
And I get a result.Succeed and the redirect to the StartPage is called.
Here is my StartPage
[Authorize(Roles = "Admin,Standardbruker")]
public class StartPageModel : PageModel
{
public void OnGet()
{
}
}
But for some reason Im not redirected to the start page. Im still on the Login page.
I know this post is missing information and I can post some more details.
I have followed this Link to article, as good as I could
but I must have missed out something, I know.
I`m using Razor Pages.
Any help is much appriciated.

You need to put your code:
app.UseAuthentication();
before your app.UseAuthorization();
Like this :
app.UseAuthentication();
app.UseAuthorization();

Yes, here it is.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using NHA_Portal.Data;
using Microsoft.EntityFrameworkCore;
using NHA_Portal.Security;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Hosting;
namespace NHA_Portal
{
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.AddLogging(loggingBuilder => {
loggingBuilder.AddConsole()
.AddFilter(DbLoggerCategory.Database.Command.Name, LogLevel.Information);
loggingBuilder.AddDebug();
});
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.AddDbContext<AppIdentityDbContext>(options =>
options.UseMySQL(Configuration.GetConnectionString("ManagementContext")));
services.AddIdentity<AppIdentityUser, AppIdentityRole>()
.AddEntityFrameworkStores<AppIdentityDbContext>();
services.ConfigureApplicationCookie(opt =>
{
opt.LoginPath = "/Security/SignIn";
opt.AccessDeniedPath = "/Security/AccessDenied";
});
services.AddRazorPages();
//services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
//services.AddDbContext<ManagementContext>(options => options.UseMySQL(Configuration.GetConnectionString("ManagementContext")));
services.AddDbContext<ManagementContext>(options => {
options.UseMySQL(Configuration.GetConnectionString("ManagementContext"));
options.EnableSensitiveDataLogging(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();
}
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.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); });
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
}
}
}

Related

Why "IApplicationBuilder" couldn't find definition for "UseGraphQL"?

I am new to GraphQL. Whenever I am running my project it shows
server is not reachable
I have crosschecked project files and I guess the issue is with the Startup.cs file. I am trying to use app.UseGraphQL in Configure function but the IDE could not suggest me a correct library for it.
This is my code:
using GraphQLMutationBasicCRUD.IService;
using GraphQLMutationBasicCRUD.Service;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using HotChocolate;
using GraphQLMutationBasicCRUD.GraphQL;
using HotChocolate.AspNetCore;
using HotChocolate.AspNetCore.Playground;
using Microsoft.AspNetCore.Http;
namespace GraphQLMutationBasicCRUD
{
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.AddSingleton<IGroupService, GroupService>();
services.AddSingleton<IStudentService, StudentService>();
services.AddGraphQL(x=> SchemaBuilder.New()
.AddServices(x)
.AddType<GroupType>()
.AddType<StudentType>()
.AddQueryType<Query>()
.AddMutationType<Mutation>()
.Create()
);
}
// 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.UsePlayground(new PlaygroundOptions
{
QueryPath = "/api",
Path = "/Playground"
});
}
app.UseGraphQL("/ api");
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
}
}
}
For full code:
GitHub
Can you modify your code like this.
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
endpoints.MapGraphQL();
});
I don't think you need app.UseGraphQL("/api");
You can browse your GraphQL client - https://localhost:5001/graphql/

.net core 5.0.2 and jwt => response 401 Unauthorized

I am following an video tutorial for identity server 4 with web api's.
And Im not sure when I went wrong.
Im getting 401 Unauthorized when I try to call api with bearer token.
In previos step, without authorization, my api worked.
This is my api controller in my TablesReach.API project:
...
namespace TablesReach.Controllers
{
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class UsersController : ControllerBase
{
private readonly DataContext _context;
public UsersController(DataContext context)
{
_context = context;
}
// GET: api/Users
[HttpGet]
public async Task<ActionResult<IEnumerable<User>>> GetUsers()
{
return await _context.Users.ToListAsync();
}
...
this is my Startup.cs of my api project:
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.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(opts =>
{
opts.Authority = "http://localhost:5000";
opts.RequireHttpsMetadata = false;
opts.ApiName = "TablesReachApi";
});
services.AddDbContext<DataContext>(opts => opts.UseInMemoryDatabase("UNWDb"));
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.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseAuthentication();
}
}
My other project TablesReach.IdentityServer is host on localhost:5000
and Im being able to get bearer token, so I assume that this project is quite OK.
identityServer startup.cs class:
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.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryApiScopes(Config.GetAllApiResources())
.AddInMemoryClients(Config.GetClients());
}
// 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();
}
//else
//{
// app.UseExceptionHandler("/Home/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.UseRouting();
//app.UseAuthorization();
//app.UseEndpoints(endpoints =>
//{
// endpoints.MapControllerRoute(
// name: "default",
// pattern: "{controller=Home}/{action=Index}/{id?}");
//});
app.UseIdentityServer();
}
}
and Config.cs:
public class Config
{
public static IEnumerable<ApiScope> GetAllApiResources()
{
return new List<ApiScope>
{
new ApiScope("TablesReachApi", "Api for solution")
};
}
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client
{
ClientId = "client",
AllowedGrantTypes = GrantTypes.ClientCredentials,
ClientSecrets =
{
new Secret("secret".Sha256())
},
AllowedScopes = { "TablesReachApi" }
}
};
}
}
Note: When I remove annotation [Authorize] from my api controller I can reach my method.
For some middleware, order matters. Authentication and authorization, for example, can't go in the order that you have put them in the API. Microsoft has some clear documentation on this for you to read here..

Why does my URL get processed before I press Enter?

I'm working through Adam Freeman's book "Pro ASP.Net Core 3" (8th edition). I am running an example of a page that uses information in a database. The Configure() method in my Startup class includes an endpoint for "/sum/{count:1000000000}". The base URL is http://localhost:5000. In Google Chrome, I type "http://localhost:5000/sum", and as soon as I type the "m", the web page is requested. If I want to get the calculation for 10 by requesting http://localhost:5000/sum/10, the page for 1000000000 is requested first. I can imagine that in a real-world application, that could end up being a problem. How do I avoid that?
Here's my startup file:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Platform.Services;
using Microsoft.EntityFrameworkCore;
using Platform.Models;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Hosting;
namespace Platform {
public class Startup {
public Startup(IConfiguration config) {
Configuration = config;
}
private IConfiguration Configuration { get; set; }
public void ConfigureServices(IServiceCollection services) {
services.AddDistributedSqlServerCache(opts =>
{
opts.ConnectionString
= Configuration["ConnectionStrings:CacheConnection"];
opts.SchemaName = "dbo";
opts.TableName = "DataCache";
});
services.AddResponseCaching();
services.AddSingleton<IResponseFormatter, HtmlResponseFormatter>();
services.AddDbContext<CalculationContext>(opts =>
{
opts.UseSqlServer(Configuration["ConnectionStrings:CalcConnection"]);
});
services.AddTransient<SeedData>();
}
public void Configure(IApplicationBuilder app,
IHostApplicationLifetime lifetime, IWebHostEnvironment env,
SeedData seedData) {
app.UseDeveloperExceptionPage();
app.UseResponseCaching();
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints => {
endpoints.MapEndpoint<SumEndpoint>("/sum/{count:int=1000000000}");
endpoints.MapGet("/", async context => {
await context.Response.WriteAsync("Hello World!");
});
});
bool cmdLineInit = (Configuration["INITDB"] ?? "false") == "true";
if (env.IsDevelopment() || cmdLineInit) {
seedData.SeedDatabase();
if (cmdLineInit) {
lifetime.StopApplication();
}
}
}
}
}

ASP.NET Core Odata Service Post not working

I implemented a ODATA Service in my ASP.NET Core application. The GET function is working fine, but I have some problems with the POST function.
If I excecute a POST the programm is excecuting the right method but I don't receive any data.
Is there anything missing in my code?
Controller:
[EnableCors]
[ODataRoutePrefix("documents")]
public class DocumentController : ODataController
{
[ODataRoute]
[EnableQuery]
public Document PushDocument([FromBody]Document doc)
{
System.Diagnostics.Debug.WriteLine("DomentID: " + doc.Id);
System.Diagnostics.Debug.WriteLine("Dokument: " + doc.RawDocument);
return doc;
}
}
Since you use [FromBody], you need to send data as Content-Type: application/json,in postman:
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddOData();
services.AddMvc(options =>
{
options.EnableEndpointRouting = false;
}).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();
}
else
{
// 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.UseMvc(b =>
{
b.MapODataServiceRoute("odata", "odata", GetEdmModel());
});
}
private static IEdmModel GetEdmModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Document>("Documents");
builder.EntitySet<Press>("Presses");
return builder.GetEdmModel();
}

.Net Core 2.x Redirect to Error Page

I have a simple ASP.Net Core 2.0 web application and I have enabled Windows Authentication in project property by enabling Windows Authentication and disabled Anonymous Authentication.
For Authorization at Application/Site level filtering by AD security group, I have the following code in 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.AddMvc();
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.RequireRole("Application - Administrator")
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
});
}
// 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.UseBrowserLink();
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseAuthentication();
//app.UseStatusCodePagesWithRedirects("/Home/Error/{0}");
//app.UseStatusCodePagesWithReExecute("/Home/Error", "?statusCode={0}");
app.UseStatusCodePagesWithReExecute("/Home/Error/{0}");
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
To handle Http 403 status code when a un-authorized user tries to access the application, it will be redirect to a custom error page. So I tried the following 3 approaches in Configure method within Startup.cs:
app.UseStatusCodePagesWithRedirects("/Home/Error/{0}");
app.UseStatusCodePagesWithReExecute("/Home/Error", "?statusCode={0}");
app.UseStatusCodePagesWithReExecute("/Home/Error/{0}");
In the HomeController, I tried both the default Error method
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
and customized one to handle specific status code:
public IActionResult Error(string errCode)
{
if (errCode == "500" || errCode == "404" || errCode == "403")
{
return View($"~/Views/Error/{errCode}.cshtml");
}
return View("~/Views/Shared/Error.cshtml");
}
And I have a simple error page 403.cshtml under /Views/Error/ folder.
But none of them works, all display this page:
I am wondering if something I missed or forgot to implement for display a formatted error page?
Thanks in advance.
I am not 100% sure but there should be 2 variations of windows authentications:
The host only allows authenticated users
When you enable Windows Authentication and disable Anonymous Users
[Authorize] and [AllowAnonymous] no effect, because unauthenticated requests never reach your application
Hence you can't / don't need to set up global filter. You might have to setup the friendly error pages on the server?
public class Startup
{
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/home/error");
}
app.UseStaticFiles();
app.UseMvcWithDefaultRoutes();
}
}
The host allows both anonymous and authenticated users
When you enable both Windows Authentication and Anonymous Users
[Authorize] requires additional setup on Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireRole("Application - Administrator")
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
app.UseStatusCodePagesWithReExecute("/error", "?code={0}");
app.UseAuthentication();
app.UseMvcWithDefaultRoutes();
}
You need to use [AllowAnonymous] on the error controller to override the [Authorize] global filter to allow anonymous requests.
[AllowAnonymous]
public class ErrorController : Controller
{
public IActionResult Index(int? code)
{
...
}
}
The problem is at the Error method, it missed the AllowAnonymous attribute to allow anonymous access to the error method when the user failed authorization.
Credit to #Calc
Try app.UseStatusCodePagesWithRedirects("/Home/Error/{0}"); in startup.configure(IApplicationBuilder app, IHostingEnvironment env)
Works on ASP.NET CORE2.0 web app
It will handle any kind of HTTP error