IConfiguration vs IOptions NET
Synchronous and Asynchronous in .NET Core
Model Binding and Validation in ASP.NET Core
ControllerBase vs Controller in ASP.NET Core
ConfigureServices and Configure methods
IHostedService interface in .NET Core
ASP.NET Core request processing
| Security in NET Core | Dry Run in Program | |
RBAC vs claims-based in ASP.NET Core |
// using Microsoft.AspNetCore.Authentication.JwtBearer;
// using Microsoft.AspNetCore.Authorization;
// using Microsoft.IdentityModel.Tokens;
// using System.Text;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("super-secret-signing-key")),
NameClaimType = "name",
RoleClaimType = "role"
};
});
builder.Services.AddAuthorization(options =>
{
// Role-based policy
options.AddPolicy("AdminOnly", policy => policy.RequireRole("Admin"));
// Claims-based policy
options.AddPolicy("CanExportReports", policy =>
policy.RequireClaim("permission", "export:reports"));
// Composite policy
options.AddPolicy("FinanceOrExporter", policy =>
policy.RequireAssertion(ctx =>
ctx.User.IsInRole("Finance") ||
ctx.User.HasClaim("permission", "export:reports")));
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class ReportsController : ControllerBase
{
// Role-based
[HttpDelete("{id}")]
[Authorize(Roles = "Admin")]
public IActionResult DeleteReport(int id) => Ok($"Deleted {id}");
// Claims-based
[HttpGet("export")]
[Authorize(Policy = "CanExportReports")]
public IActionResult Export() => Ok("Exported CSV");
// Composite policy
[HttpPost("finance-export")]
[Authorize(Policy = "FinanceOrExporter")]
public IActionResult FinanceExport() => Ok("Finance export done");
}
// using Microsoft.AspNetCore.Identity;
// using System.Security.Claims;
public static async Task SeedAsync(UserManager<IdentityUser> users, RoleManager<IdentityRole> roles)
{
if (!await roles.RoleExistsAsync("Admin"))
await roles.CreateAsync(new IdentityRole("Admin"));
var user = await users.FindByEmailAsync("user@example.com")
?? new IdentityUser { UserName = "user@example.com", Email = "user@example.com", EmailConfirmed = true };
if (user.Id == null) await users.CreateAsync(user, "Pass@1234");
await users.AddToRoleAsync(user, "Admin"); // Role
await users.AddClaimAsync(user, new Claim("permission", "export:reports")); // Claim
await users.AddClaimAsync(user, new Claim("tenant", "42")); // Claim
}
// using System.IdentityModel.Tokens.Jwt;
// using System.Security.Claims;
// using Microsoft.IdentityModel.Tokens;
var claims = new List<Claim>
{
new("name", "shiv"),
new("role", "Admin"), // aligns with RoleClaimType = "role"
new("permission", "export:reports"), // app-specific permission
new("tenant", "42")
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("super-secret-signing-key"));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
claims: claims,
expires: DateTime.UtcNow.AddHours(1),
signingCredentials: creds);
var jwt = new JwtSecurityTokenHandler().WriteToken(token);
public class SameTenantRequirement : IAuthorizationRequirement {}
public class SameTenantHandler : AuthorizationHandler<SameTenantRequirement, string>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
SameTenantRequirement requirement,
string resourceTenantId)
{
var userTenant = context.User.FindFirst("tenant")?.Value;
if (!string.IsNullOrEmpty(userTenant) && userTenant == resourceTenantId)
context.Succeed(requirement);
return Task.CompletedTask;
}
}
// Registration
builder.Services.AddAuthorization(o =>
{
o.AddPolicy("SameTenantOnly", p => p.AddRequirements(new SameTenantRequirement()));
});
builder.Services.AddSingleton<IAuthorizationHandler, SameTenantHandler>();
// Usage (e.g., in controller)
[Authorize(Policy = "SameTenantOnly")]
public async Task<IActionResult> Get(string tenantId, [FromServices] IAuthorizationService auth)
{
var ok = await auth.AuthorizeAsync(User, tenantId, "SameTenantOnly");
return ok.Succeeded ? Ok() : Forbid();
}
| Security in NET Core | Dry Run in Program | |