Skip to main content
ESP Santa Fe de Antioquia uses ASP.NET Core Identity for authentication and authorization, with cookie-based authentication for session management.

Identity Configuration

Identity is configured in Startup.cs:32 with custom options:
services.AddIdentity<IdentityUser, IdentityRole>(
    options => options.SignIn.RequireConfirmedAccount = true)
   .AddEntityFrameworkStores<ApplicationDbContext>()
   .AddDefaultTokenProviders();
RequireConfirmedAccount: Users must confirm their email address before they can sign in, enhancing security.

Authentication Flow

Password Requirements

Password policies are configured in Startup.cs:42:
services.Configure<IdentityOptions>(options =>
{
    // Password settings
    options.Password.RequireDigit = false;
    options.Password.RequireLowercase = false;
    options.Password.RequireNonAlphanumeric = false;
    options.Password.RequireUppercase = true;
    options.Password.RequiredLength = 4;
    options.Password.RequiredUniqueChars = 0;
});
SettingValueDescription
RequiredLength4Minimum password length
RequireUppercasetrueMust contain uppercase letter
RequireDigitfalseNumbers optional
RequireLowercasefalseLowercase optional
RequireNonAlphanumericfalseSpecial characters optional
RequiredUniqueChars0No unique character requirement

Account Lockout

Protection against brute-force attacks is configured in Startup.cs:52:
services.Configure<IdentityOptions>(options =>
{
    // Lockout settings
    options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
    options.Lockout.MaxFailedAccessAttempts = 5;
    options.Lockout.AllowedForNewUsers = true;
});
How it works:
  1. After 5 failed login attempts
  2. Account is locked for 5 minutes
  3. Applies to all users, including new accounts
Attempt 1: Failed - No lockout
Attempt 2: Failed - No lockout
Attempt 3: Failed - No lockout
Attempt 4: Failed - No lockout
Attempt 5: Failed - Account locked for 5 minutes

[5 minutes pass]

Next attempt: Allowed (counter resets if successful)

User Settings

User configuration in Startup.cs:57:
services.Configure<IdentityOptions>(options =>
{
    // User settings
    options.User.AllowedUserNameCharacters =
        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
    options.User.RequireUniqueEmail = false;
});
  • Allowed Username Characters: Letters, numbers, and -._@+ symbols
  • RequireUniqueEmail: false allows multiple accounts with same email
Cookie settings are configured in Startup.cs:63:
services.ConfigureApplicationCookie(options =>
{
    // Cookie settings
    options.Cookie.HttpOnly = true;
    options.ExpireTimeSpan = TimeSpan.FromMinutes(180);

    options.LoginPath = "/Identity/Account/Login";
    options.AccessDeniedPath = "/Identity/Account/AccessDenied";
    options.SlidingExpiration = true;
});

Token Lifespans

Data protection tokens (password reset, email confirmation) are configured in Startup.cs:38:
services.Configure<DataProtectionTokenProviderOptions>(o =>
    o.TokenLifespan = TimeSpan.FromDays(7));
Token Types:
  • Email confirmation tokens: Valid for 7 days
  • Password reset tokens: Valid for 7 days
  • Phone number confirmation: Valid for 7 days

Identity Pages

The application uses scaffolded Identity pages in the Areas/Identity/ directory:
Account Management:
  • /Identity/Account/Login - User login
  • /Identity/Account/Logout - User logout
  • /Identity/Account/Register - New user registration
  • /Identity/Account/ForgotPassword - Password reset request
  • /Identity/Account/ResetPassword - Password reset form
  • /Identity/Account/AccessDenied - Authorization failure
Profile Management (/Identity/Account/Manage/):
  • Index - Profile information
  • Email - Change email
  • ChangePassword - Change password
  • TwoFactorAuthentication - 2FA settings
  • PersonalData - GDPR data management
  • DeletePersonalData - Account deletion

Database Schema

Identity extends the database with authentication tables:
// ApplicationDbContext.cs:9
public class ApplicationDbContext :
    IdentityDbContext<IdentityUser, IdentityRole, string>
{
    // Application DbSets
    public DbSet<Category> Categories { get; set; }
    public DbSet<Product> Products { get; set; }
    // ... more entities
}
Identity Tables:
  • AspNetUsers - User accounts
  • AspNetRoles - User roles
  • AspNetUserRoles - User-role relationships
  • AspNetUserClaims - Custom user claims
  • AspNetUserLogins - External authentication providers
  • AspNetUserTokens - Authentication tokens
  • AspNetRoleClaims - Role-based claims

Authorization in Controllers

Protect actions with the [Authorize] attribute:
using Microsoft.AspNetCore.Authorization;

[Authorize]  // Entire controller requires authentication
public class ProductsController : Controller
{
    public async Task<IActionResult> Index()
    {
        // Only authenticated users can access
        return View(await _productService.GetAll());
    }
    
    [AllowAnonymous]  // Override - allow public access
    public async Task<IActionResult> ListProducts()
    {
        return View(await _productService.GetAll());
    }
}

Role-Based Authorization

[Authorize(Roles = "Admin")]
public class AdminController : Controller
{
    public IActionResult Dashboard()
    {
        // Only Admin role can access
        return View();
    }
}

[Authorize(Roles = "Admin,Manager")]
public IActionResult Reports()
{
    // Admin OR Manager can access
    return View();
}

Claims-Based Authorization

[Authorize(Policy = "RequireAdminRole")]
public class AdminController : Controller
{
    // Protected by custom policy
}
Define policies in Startup.cs:
services.AddAuthorization(options =>
{
    options.AddPolicy("RequireAdminRole", 
        policy => policy.RequireRole("Admin"));
});

Authorization in Views

Show/hide UI elements based on authentication:
@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager

@if (SignInManager.IsSignedIn(User))
{
    <a asp-area="Identity" asp-page="/Account/Manage/Index">
        Hello @User.Identity.Name!
    </a>
    <form asp-area="Identity" asp-page="/Account/Logout">
        <button type="submit">Logout</button>
    </form>
}
else
{
    <a asp-area="Identity" asp-page="/Account/Register">Register</a>
    <a asp-area="Identity" asp-page="/Account/Login">Login</a>
}
Role-based view rendering:
@if (User.IsInRole("Admin"))
{
    <a asp-controller="Admin" asp-action="Dashboard">Admin Dashboard</a>
}

Middleware Pipeline

Authentication middleware is registered in Startup.cs:119:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseRouting();
    
    // Authentication must come before Authorization
    app.UseAuthentication();
    app.UseAuthorization();
    
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
        endpoints.MapRazorPages();  // Required for Identity pages
    });
}
Order Matters: UseAuthentication() must be called before UseAuthorization(). Authentication identifies the user, authorization determines what they can access.

Security Best Practices

HTTPS Only

Always use HTTPS in production to encrypt authentication cookies and prevent interception

Strong Passwords

Enforce strong password requirements (8+ characters, complexity requirements)

Account Lockout

Enable lockout to prevent brute-force attacks

Email Confirmation

Require email confirmation to verify user identity

Cookie Security

Use HttpOnly, Secure, and SameSite cookie attributes

Token Expiration

Keep token lifespans reasonable (not too long)

Production Hardening

For production environments, enhance security:
options.Password.RequireDigit = true;
options.Password.RequireLowercase = true;
options.Password.RequireNonAlphanumeric = true;
options.Password.RequireUppercase = true;
options.Password.RequiredLength = 8;
options.Password.RequiredUniqueChars = 4;

User Management

Access user information in controllers:
public class ProfileController : Controller
{
    private readonly UserManager<IdentityUser> _userManager;

    public ProfileController(UserManager<IdentityUser> userManager)
    {
        _userManager = userManager;
    }

    public async Task<IActionResult> Index()
    {
        var user = await _userManager.GetUserAsync(User);
        var roles = await _userManager.GetRolesAsync(user);
        
        return View(new ProfileViewModel 
        { 
            Email = user.Email,
            Roles = roles
        });
    }
}

Next Steps

API Reference

Explore controllers and authorization

Database Schema

Review Identity database tables

Services Layer

Understand service layer patterns

Deployment

Deploy with secure authentication

Build docs developers (and LLMs) love