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

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

Related

Startup.vb DonĀ“t recognize StarttupAuth.vb Class [duplicate]

I'm getting an error when I'm attempting to run my page says that,
The name 'ConfigureAuth' does not exist in the current context
in my Stratup Class. I'm sure all AspNet Identity libraries are installed. What do I need to do next, to try to fix this?
using Microsoft.Owin;
using Owin;
[assembly: OwinStartupAttribute(typeof(project_name.Startup))]
namespace project_name
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
}
}
}
If you are using default Visual Studio project template, the ConfigureAuth method could be found in partial class Startup.Auth.cs. So make sure you didn't break anything when modifying project structure.
This is an example of ConfigureAuth method:
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context and user manager to use a single instance per request
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/api/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
}
I had similar issue, To fix the issue I removed .App_Start from namespace in Startup.Auth.cs file. After that I was able to see the reference.
It is either:
[assembly: **OwinStartup**(typeof(Project-Name.Startup))]
namespace project-name
{
public partial class Startup
{
public void **Configuration**(IAppBuilder app)
{
OR
[assembly: **OwinStartupAttribute**(typeof(Project-Name.Startup))]
namespace project-name
{
public partial class Startup
{
public void **ConfigureAuth**(IAppBuilder app)
{
Either rename OwinStartupAttribute to OwinStartup
OR Configuration to ConfigureAuth
Kindly I note that the two partial classes (Startup.Auth.cs and Startup.cs) should be in the same namespace which is the root of the project, just change the namespace of Startup.Auth.cs to the same namespace of the Startup.cs
Make sure when you originally create the project that there are no spaces in the name.
e.g. my app was called "DevOps Test" which was giving me errors when I ran it.
I recreated it as "DevopsTest" and no longer had these issues
namespace PAYOnline.App_Start
delete App_Start only namespace PAYOnline => It's welldone

How To Implement .Net Core Identity on Asp.Net Core 5.0 Project Following Repository Pattern?

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();

Restrict account registration to only Admin users with asp.net identity authentication

I am creating a Blazor server app that requires authenticated users in order to prevent external access, and I would like to limit the ability to register new accounts to be only available to Administrator users to prevent unwanted accounts from being created.
I'm using Identity user accounts, scaffolded out for Blazor. Solutions like this at least disable the registration, but from there I need to be able to enable it again for administrative users. I attempted to recreate the register page as a Blazor component, however, using the generated RegisterModel did not seem to work for me.
Upon a large amount of searching - the answer ended up being relatively simple. Muhammad Hammad Maroof's solution although technically correct, confused me and was mostly unhelpful for working with the register page specifically.
As I am using Role-Based Authentication scaffolded out from Blazor - in a seperate razor page I use this code to set up roles:
#code {
protected override async Task OnParametersSetAsync()
{
await SetUpAuth();
}
private async Task SetUpAuth()
{
const string Manager = "Manager";
string[] roles = { Manager };
foreach (var role in roles)
{
var roleExist = await roleManager.RoleExistsAsync(role);
if (!roleExist)
{
await roleManager.CreateAsync(new IdentityRole(role));
}
}
var user = await userManager.FindByEmailAsync(config.GetValue<string>("AdminUser"));
if (user != null)
{
await userManager.AddToRoleAsync(user, Manager);
}
}
}
Allowing the appropriate user to be marked as an administrator. This page has the [AllowAnonymous] tag on it in order to allow the administrative user as dictated by "AdminUser": "SomeEmail#test.com", in the appsettings.json page to be able to access the site on initial setup.
Preventing access to the Blazor site itself from anonymous users was as simple as adding this line to ConfigureServices in the startup class (Code taken from Microsoft Docs)
services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
From this, allowing access to the register page was significantly easier than I had initially thought (likely due to my lack of .net experience). To do so, all you have to do is locate the Register.cshtml.cs page (I couldn't initially find the controller method Muhammad had mentioned) which I did by using visual studio to right click on the Register Model and then go to definition. This should take you to the Register.cshtml.cs page with the RegisterModel class. In order to restrict access to this page for only a specific role of users, all you have to do is change the [AllowAnonymous] tag above the class to look similar to this:
[Authorize(Roles ="Manager")]
public class RegisterModel : PageModel
It's important to note that the same technique used to secure the register page could be used to secure any of the of the other scaffolded Identity pages. For applications where you may have more than a few roles, the method provided by Muhammad of using policy based authorization may be the way to go, and this link he provided is a great tutorial for setting up and using that form of authentication.
//FORCE autentication for all RAZOR PAGES except [AllowAnonymous]
services.AddControllers(config => {
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
});
Only adding this code to my startup.cs solved my problem.
Here's how I am doing it in asp.net core mvc app
C# Startup class:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthorization(options =>
{
options.AddPolicy(ADMIN_ACCESS, policy => policy.RequireRole($"{UserType.Admin}"));
});
}
[Authorize("AdminAccess")]
public class AdminController : Controller
{
//Some action methods here
}

No service for type 'Microsoft.AspNetCore.Identity.SignInManager When

I am getting
InvalidOperationException: No service for type
'Microsoft.AspNetCore.Identity.SignInManager
1[Authorization.IdentityModels.ApplicationUser]' has been registered.
when I run my ApsCore MVC website.
this are segments from my code:
ConfigureServices:
services.AddDbContext<ApplicationDbContext>(options =>
options.UseNpgsql(configuration["Data:DefaultConnection:ConnectionString"]));
services.AddIdentity<ApplicationUser, IdentityRole<Guid>>()
.AddEntityFrameworkStores<ApplicationDbContext, Guid>()
.AddDefaultTokenProviders();
Configure:
app.UseIdentity();
ApplicationDbContext.cs
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, IdentityRole<Guid>, Guid>
ApplicationUser.cs
public class ApplicationUser : IdentityUser<Guid>
I will be very happy if you can help me.
Faced with the same issue after moving my Identity classes to Guid and found solution here:
You probably need to change your login partial view to use the new
user type IdentityUser
Within Views/Shared/_LoginPartial.cshtml, I just changed
#using Microsoft.AspNetCore.Identity
#inject SignInManager<IdentityUser> SignInManager
#inject UserManager<IdentityUser> UserManager
To
#using Microsoft.AspNetCore.Identity
#inject SignInManager<MyUser> SignInManager
#inject UserManager<MyUser> UserManager
and that worked for me.
Not sure if you are still seeing this issue, but here's some help for anyone else that stumbles upon this. (Note that the specifics are for version 1, but the need for an injected dependency not being available is the same.)
The issue is coming from some class in your application requiring a SignInManager in its constructor, but there isn't an implementation associated with it in the dependency injection setup.
To fix, in your Startup class, in the ConfigureServices method, register the SignInManager class in the services. For example:
services.AddScoped<SignInManager<ApplicationUser>, SignInManager<ApplicationUser>>();
The AddIdentity extension method may have been updated since the original question was asked to add this in, but the same error type will show up for anything the IoC container can't resolve.
This is what worked for me. I had added identity when i was creating the project which made it possible for the framework to inject UserManager<IdentityUser> and SignInManager<IdentityUser> into my _loginPartial View. What i did was to change the Type<TUser> from <IdentityUser> to <ApplicationUser>(ApplicationUser is the identity class i want to use in the project which inherits from IdentityUser class) and everything works fine.

MVC SQL No Connection String Named Could Be Found in the Application Config File EF6

I have searched through a number of questions(No Connection String Named MyEntities Could Be Found In The Application Config), but most seem to deal with multiple projects in a solution, in this case I have only one project in one solution. Also this is my first MVC Project with EF6. When going to add a controller I get this error:
This is my Web.Config
And This is My Solution Explorer
I know the error references an Application Config File, but I do not have an app Config file, nor do I know where to put it or how to create it.
EDIT, Here is the code for the db context
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext() : base("name=DBConnection"){}
public System.Data.Entity.DbSet<zzz.Models.Supplier> Suppliers { get; set; }
}