Elarion

ASP.NET Core Identity

Optional ASP.NET Core Identity integration that composes onto a plain DbContext — no IdentityDbContext inheritance, snake_case-ready.

Elarion's ASP.NET Core Identity support is split across two optional packages:

  • Elarion.EntityFrameworkCore.Identity — the web-free Identity model: the [GenerateElarionIdentity] marker and the ApplyElarionIdentity helper. It depends only on EF Core + the Identity stores package, so the project that owns your DbContext can model Identity without referencing the ASP.NET shared framework.
  • Elarion.AspNetCore.Identity — the host wiring: AddElarionIdentity, the Identity ICurrentUser claim mapping, and the transport-neutral authorizer. This one pulls in ASP.NET Core.

Identity is one authentication provider among many — authorization itself does not depend on either package. The distinguishing trait is composition over inheritance: your application DbContext stays a plain DbContext and composes the Identity model, rather than deriving from IdentityDbContext.

In a layered solution, reference Elarion.EntityFrameworkCore.Identity from the persistence/application project (where the DbContext and [GenerateElarionIdentity] live) and Elarion.AspNetCore.Identity from the web host (where AddElarionIdentity runs). The data layer composes the Identity model with no web-framework dependency. In a single-project host, reference both.

Wiring

// Program.cs
builder.Services.AddElarionIdentity<ApplicationUser, ApplicationRole, Guid, AppDbContext>();
builder.Services.AddDbContext<AppDbContext>(o => o.UseNpgsql(connectionString));

AddElarionIdentity<TUser, TRole, TKey, TDbContext>:

  • registers AddIdentity<TUser, TRole>() + AddEntityFrameworkStores<TDbContext>() (+ default token providers),
  • maps ICurrentUser to the Identity claim types (NameIdentifier/Email/Role, overridable), and
  • registers the transport-neutral authorizer via AddElarionAuthorization, so handler [Require*] attributes are enforced.

Cookie/authentication policy (ConfigureApplicationCookie, login endpoints, UseAuthentication, UseElarionCurrentUser) stays the host's job — the package wires Identity and authorization, not your sign-in UX.

The context composes Identity

AddEntityFrameworkStores only needs the Identity entities mapped — it does not require IdentityDbContext. Annotate a plain [GenerateDbSets] context (the [GenerateElarionIdentity] marker and its generator come from Elarion.EntityFrameworkCore.Identity, so this assembly needs no web dependency):

[GenerateDbSets]
[GenerateElarionIdentity<ApplicationUser, ApplicationRole, Guid>(SnakeCase = true)]
public sealed partial class AppDbContext(DbContextOptions<AppDbContext> options) : DbContext(options) {
    protected override void OnModelCreating(ModelBuilder modelBuilder) => ConfigureEntities(modelBuilder);
}

public sealed class ApplicationUser : IdentityUser<Guid>;
public sealed class ApplicationRole : IdentityRole<Guid>;

The bundled generator emits the seven Identity DbSets (db.Users, db.Roles, db.UserClaims, …) and applies the full Identity model configuration — keys, composite keys, unique normalized indexes, relationships, max-lengths — through the EF generator's neutral OnEntitiesConfigured seam. So the single ConfigureEntities(modelBuilder) call configures both your domain entities (from [EntityConfiguration]) and Identity, with no <TUser, TRole, TKey> repeated at the call site and no IdentityDbContext in the hierarchy. (Requires [GenerateDbSets] on the same context, else ELIDN001.)

snake_case

SnakeCase = true (the default) makes the generated Identity model use snake_case table, column, and index names directly — users, roles, user_claims, normalized_user_name, ix_users_normalized_user_name, … — instead of the ASP.NET AspNet* PascalCase defaults. It is self-contained: no EFCore.NamingConventions dependency, and the names match what that convention would produce, so an app already using it for domain tables sees a consistent schema. Set SnakeCase = false to keep the Identity defaults. The underlying primitive, modelBuilder.ApplyElarionIdentity<TUser, TRole, TKey>(snakeCase) (also in Elarion.EntityFrameworkCore.Identity), is public for advanced hosts that prefer to call it directly.

What stays in your app

The package is deliberately minimal. Role→permission policy, seeding, sign-in/registration endpoints, and the user-management surface stay app-owned — they are domain decisions, not framework mechanics. Permissions are typically issued as a permission claim (the default AuthorizationOptions.PermissionClaimType) on roles, and enforced on handlers with [RequirePermission]. You no longer hand-maintain the list of permissions, though: inject IPermissionCatalog to enumerate every [RequirePermission]/[RequireRole] across your modules when seeding.

See also

On this page