How To Implement .Net Core Identity on Asp.Net Core 5.0 Project Following Repository Pattern? - asp.net-core

I am working on the .Net Core 5.0 technology and my current project structure is as follow (In the same solution):
Asp.Net Core 5.0 Web API Project
Asp.Net Core 5.0 Web Application Project For Admin Users (Client-Side)
Asp.Net Core 5.0 Web Application Project For Super Admin (Client-Side)
Asp.Net Core 5.0 Class Library (For Repository Pattern)
The Web API project is simply an API project that will respond to Admin/Super Admin Client applications by providing resources for database operations (Crud Operation).
The Repository Project is where the whole of my application logic exists including Interfaces and their implementations. The repository pattern is injected on API Controllers where the controller method performs the particular operation using the UnitOfWork pattern of the Repository Project.
I have implemented .Net Core Identity (Not Scaffolded Identity, I have just inherited the ApplicationContext class of repository pattern from IdentityDbContext while passing the custom AppliationUser class to it) on the repository project and everything works fine even after running the code first migration for adding identity tables and customizing the IdentityUser.
What I want to achieve is to use Identity Scaffolding on both of my client applications (For Admin and Super Admin Portals), in order to allow Super Admin for adding Roles and assigning Users to those Roles.
With the Admin portal, I will be allowing Admins to manage their own users.
However, I am facing issues in dealing with the startup.cs part on each of my Admin and Super Admin portals. I do want to use only the ApplicationContext.cs class on Repository Project for all of my Database related operations. But, scaffolding the identity (on Super Admin portal results in creating a data folder with a separate AppliationDbContext.cs class and migrations folder) and most probably this will be the case with the Admin portal (I didn't try it on the Admin portal).
Note: I have scaffolded the identity on the Super Admin portal using Command Line Interface (CMD) because VS19 throws an error when I try to scaffold identity by right-clicking on the project and choosing to add scaffolding).
What I need now is to use the Identity tables like the Roles table for allowing Super Admin to create new roles. But when I try to run my project and execute the code where Super Admin creates a role, it shows me an error in the popup/alert box window saying:
Here is my code for saving the role using ajax call to my API project:
function SaveRole() {
var roleName = $('#roleName').val();
$.ajax({
url: APIHost + 'api/SuperAdmin/AddNewRole',
data: JSON.stringify(roleName),
type: 'POST',
contentType: 'application/json;charset=utf-8',
dataType: 'json',
success: function (result) {
if (result) {
$("#closeNewRoleModal").click();
}
},
error: function (errormessage) {
alert(errormessage.responseText);
}
});
}
And API SuperAdmin Controller code:
[Route("api/SuperAdmin")]
[ApiController]
public class SuperAdminController : ControllerBase
{
private readonly IUnitOfWork _unitOfWork;
private RoleManager<IdentityRole> _roleManager;
private UserManager<ApplicationUser> _userManager;
public SuperAdminController(IUnitOfWork unitOfWork, RoleManager<IdentityRole> roleManager, UserManager<ApplicationUser> userManager)
{
_unitOfWork = unitOfWork;
_roleManager = roleManager;
_userManager = userManager;
}
[HttpPost]
[Route("AddNewRole")]
public async Task<IActionResult> AddNewRole(string role)
{
await _roleManager.CreateAsync(new IdentityRole(role));
return new JsonResult(true);
}
}
Update:
I have removed the Data Folder and Migrations Folder added by Identity Scaffolding. And on the startup.cs class of my Super Admin portal, I am doing this on the ConfigureServices method:
services.AddDbContext<ApplicationContext>();
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationContext>()
.AddDefaultTokenProviders();
Please note that the ApplicationContext is the actual context class within Repository Project which I am using for database operations and is inherited from the IdentityDbContxt base class.

It was my mistake that I was completely avoiding the startup.cs class of Super Admin portal. I thought that each application will be using the startup.cs class of API Project.
I included the following code in ConfigureServices method on my Admin Portal's startup.cs class and the issue was resolved:
services.AddDbContext<ApplicationContext>();
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationContext>()
.AddDefaultTokenProviders()
.AddDefaultUI();

Related

Azure Application Insight wrong shows URL in logs for ASP.NET Core 6 Web API application with API versioning

I have an ASP.NET Web API application running on .NET 4.8. In this app, I'm using standard Microsoft API versioning from Microsoft.AspNet.WebApi.Versioning and Microsoft.AspNet.WebApi.Versioning.ApiExplorer.
For instance:
[ApiVersionExtended(SupportedApiVersions.V9)]
[RoutePrefix("v{version:apiVersion}/telemetry")]
public sealed class TelemetryController : ApiController
{
where ApiVersionExtended - my filter. In Azure Application Insight requests to my API are shown with the correct version. For instance:
But after migration to .NET 6, I lost the correct version number in AI logs, for instance:
My code has several changes after migration to .NET 6
[ApiController]
[AllowAnonymous]
[ApiVersionExtended]
[Route("v{version:apiVersion}/telemetry")]
public sealed class TelemetryController : ApiController
{
[HttpGet("ipInfo")]
public async Task<IActionResult> GetIpInfoAsync(CancellationToken cancellationToken)
{
/* some code here */
}
}
I can't find the analog [RoutePrefix] attribute in .NET 6.
Might someone know what the reason for this issue is? And how I can fix it?
As suggested by #Peter Bons, this can be the issue with your existing Nuget Package.
The Nuget Package required to Implement API Versioning in .NET 6 Core Web API is Microsoft.AspNetCore.Mvc.Versioning
Install Microsoft.AspNetCore.Mvc.Versioning Nuget Package
In Program.cs add the below services
To add versioning for WebAPI
builder.Services.AddApiVersioning(opt =>
{
opt.DefaultApiVersion = new Microsoft.AspNetCore.Mvc.ApiVersion(2, 0);
opt.AssumeDefaultVersionWhenUnspecified = true;
opt.ReportApiVersions = true;
opt.ApiVersionReader = ApiVersionReader.Combine(new UrlSegmentApiVersionReader(),
new HeaderApiVersionReader("x-api-version"),
new MediaTypeApiVersionReader("x-api-version"));
});
To Add versioning with Swagger, add the below services
builder.Services.AddSwaggerGen(Options => Options.SwaggerDoc("v1", new OpenApiInfo { Title = "Audit Self Serve platform", Version = "v1" }));
Use MapToApiVersion attribute to assign each action to a distinct version
[MapToApiVersion("1.0")]
[HttpGet]
OutPut:

When scaffolding identity in Blazor Server 6 and overriding IdentityUser, Login and register do not work anymore

Steps to reproduce:
Create new Blazor 6 Server project, with individual account
Updated all Nuget packages to the latest version
Override the default identityuser class (applicationuser) and add some custom properties.
Setup DBContent as following:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
}
Change IdentityUser to ApplicationUser here
Scaffolded identity, so all Razor account views are created.
Add and apply an EF migration, the extra properties are added to the database.
Change startup.cs as following:
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
App runs fine but when I try the register a user, it fails on the following:
I created this test project from scratch, no upgrades. So it created the user (verified in database), but when retrieving it from the database fails.
Logging in with this user also fails with a similar error
Did someone get this working ? Or have some guidance on what I'm doing wrong ?
Thanks !
Well, I found a workaround. I scaffolded identity with the default IdentityUser, then went through all the Identity pages and changed the user class.
That worked.
These properties were nullable (strings) but the new columns were added to the database

User.Claims is empty after upgrading from ASP.NET Core 3.1 to ASP.NET 5.0

After upgrading from ASP.NET Core 3.1 to version 5, context.User.Claims is empty in
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MyRequirement requirement)
in
public class MyRequirementHandler : AuthorizationHandler<MyRequirement>
I'm using the Authorization header with a bearer token with JWT. I can see that header being set correctly when looking at the HttpContext.Request.Headers but it doesn't seem to be parsed.
This is set up on a Grpc Service with the [Authorize] attribute.
With ASP.NET Core 3.1, it worked fine. I went through the official migration guide but their references regarding authorisation were only for Azure Active Directory.
I'm using IdentityServer4 which is hosted within that ASP.NET Core app as a middleware (app.UseIdentityServer();)
What did I forget to modify to get ASP.NET Core to parse the authorisation header correctly?
Update:
I checked it in more details and noticed that it's failing because it can't verify the audience (aud) - and yes on the newly created tokens the audience is missing (the old tokens had the audience). Also I noticed that a custom scope, which I was adding in
public override async Task GetProfileDataAsync(ProfileDataRequestContext context)
inside my custom
public class ProfileService : ProfileService<ApplicationUser>
is also missing after the update. This is how the IdentityServer is configured:
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, AppIdentityDbContext>()
.AddProfileService<ProfileService>()
.AddInMemoryIdentityResources(AuthResources.GetIdentityResources())
.AddInMemoryApiResources(AuthResources.GetApiResources())
.AddInMemoryClients(TestClientsRequired
? ClientsForTesting.GetTestClients()
: Clients.GetDefaultClients());
After figuring out that the issue might have been due to a missing audience (aud) I looked further and found Missing "aud" claim in access token - the answer was, to explicitly add the audience as a claim and also set the scope one more time, and it worked.
For me this looks the following way:
public static IEnumerable<ApiResource> GetApiResources()
{
yield return ApiResourceBuilder
.IdentityServerJwt(MyWebApiResource)
.AllowAllClients()
.Build()
.AddUserClaims()
.AddScopes(); // <- this is new
}
private static T AddUserClaims<T>(this T resource)
where T : Resource
{
resource.UserClaims.Add(Constants.CustomClaimTypes.MyRoles);
resource.UserClaims.Add(JwtClaimTypes.Audience); // <- this is new
return resource;
}
// this whole method is new ->
private static T AddScopes<T>(this T resource)
where T : ApiResource
{
resource.Scopes.Add(MyWebApiResource);
return resource;
}

Asp.Net Core 3.1 Web Application, Api page not found issue

My Environment Windows 10. Visual Studio 2019 Professional, Asp.Net Core 3.1
I am following a Pluralsight course to teach myself Asp.Net Core 3.1. Following the instructor, I have created the web application. Everything goes well until the instructor adds an api controller to the application. It works for him but not for me.
Here's my api controller
namespace OdeToFood.Api
{
[Route("api/[controller]")]
[ApiController]
public class RestaurantsController : ControllerBase
{
private readonly OdeToFoodDbContext _context;
public RestaurantsController(OdeToFoodDbContext context)
{
_context = context;
}
// GET: api/Restaurants
[HttpGet]
public async Task<ActionResult<IEnumerable<Restaurant>>> GetRestaurants()
{
return await _context.Restaurants.ToListAsync();
}
// GET: api/Restaurants/5
[HttpGet("{id}")]
public async Task<ActionResult<Restaurant>> GetRestaurant(int id)
{
var restaurant = await _context.Restaurants.FindAsync(id);
if (restaurant == null)
{
return NotFound();
}
return restaurant;
}
. . . . .
Here's my project structure and hierarchy.
When I rebuild my project, and call the app from local IIS Express, i.e. https://localhost:44351/ It loads fine. I can interact fully, browse and CRUD entities. However when I point to any api url, e.g. https://localhost:44351/api/Restaurants or https://localhost:44351/api/Restaurants/2 I get "This localhost page can’t be found". The api simply does not load or respond in any way.
I am familiar with MVC5 where, when creating a new project, in the create project wizard scaffolding, you could check a box to add api functionality. I am not seeing this in VS2019 for Asp.Net Core 3.1 We Apps.
I promise you have have done my homework before asking this question here. I have googled to death. I have seen MS articles on core 3.1 breaking changes. I have looked at online project templates. I have searched stackoverflow. Maybe my search terms are flawed and I'm simply missing something simple.
Questions:
Why is the api shown above not loading?
Is there a way to add api functionality to an existing Asp.Net Core 3.1 Web Application or do I need to create a separate api project?
Is there a way to create a new Asp.Net Core 3.1 Web Application with api functionality included?
My thanks in advance
Kieran
If you'd like to add web APIs feature into an existing Razor Pages project, you need to do additional configuration, like below.
public void ConfigureServices(IServiceCollection services)
{
//add services for controllers
services.AddControllers();
services.AddRazorPages();
//...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//...
app.UseRouting();
//...
app.UseEndpoints(endpoints =>
{
//add endpoints for controller actions
endpoints.MapControllers();
endpoints.MapRazorPages();
});
}
Testing code of controller and action(s)
[Route("api/[controller]")]
[ApiController]
public class RestaurantsController : ControllerBase
{
public IActionResult GetRestaurants()
{
return Ok("Restaurants List Here");
}
}
Test Result

Migrate Principal from ASP.NET Web API 2 to ASP.NET Core (AuthenticationFilter)

I'm thinking about how can I migrate a ASP.NET Web API 2 project to ASP.NET Core.
Current project details:
All API controllers are inheriting a BaseController.
BaseController is decorated with a custom attribute (CustomAuthenticationAttribute)
CustomAuthenticationAttribute implements IAuthenticationFilter and inside AuthenticateAsync method:
Based on the HTTP headers I'm retrieving details about the user from the database
In case the user is not found, I'm populating HttpAuthenticationContext.ErrorResult and return (cutting the pipeline)
If I find the user, a statement similar to this is executed: HttpAuthenticationContext.Principal = new GenericPrincipal(identity, new string[] { }) in order to set the principal.
The BaseController contains the following code:
protected MyIdentityClass Identity
{
get
{
if (RequestContext.Principal == null)
{
return null;
}
return RequestContext.Principal.Identity as MyIdentityClass ;
}
}
I am able to access the Identity inside any API method.
Inside unit tests, I can assign the principal with the following code:
Thread.CurrentPrincipal = new GenericPrincipal(identity, new string[] { });
My question is this: How can I port this code to ASP.NET Core without modifying all my API controllers and test classes? I've already read Migrate from ClaimsPrincipal.Current but it doesn't satisfy my needs.