windows integrovana autentizace - zatim jeste uplne nefunguje

This commit is contained in:
2026-02-28 18:17:13 +01:00
parent 59f1a7080d
commit 30cdd552dd
6 changed files with 165 additions and 34 deletions

View File

@@ -31,7 +31,7 @@
</div> </div>
<div class="nav-item px-3"> <div class="nav-item px-3">
<NavLink class="nav-link" href="auth"> <NavLink class="nav-link" href="secure">
<span class="bi bi-lock-nav-menu" aria-hidden="true"></span> Auth Required <span class="bi bi-lock-nav-menu" aria-hidden="true"></span> Auth Required
</NavLink> </NavLink>
</div> </div>

View File

@@ -1,4 +1,4 @@
@page "/auth" @page "/secure"
@using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Authorization

View File

@@ -1,3 +1,6 @@
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Negotiate;
using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@@ -7,6 +10,13 @@ using RIIT.Data;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
// ===== Auth mode switches (configurable via appsettings.json) =====
var authMode = builder.Configuration["Auth:Mode"]?.Trim() ?? "Internal";
var windowsEnabled = string.Equals(authMode, "Windows", StringComparison.OrdinalIgnoreCase);
// Detect IIS / IIS Express hosting (intranet scenario)
var runningUnderIis = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("ASPNETCORE_IIS_PHYSICAL_PATH"));
// Add services to the container. // Add services to the container.
builder.Services.AddRazorComponents() builder.Services.AddRazorComponents()
.AddInteractiveServerComponents(); .AddInteractiveServerComponents();
@@ -15,21 +25,40 @@ builder.Services.AddCascadingAuthenticationState();
builder.Services.AddScoped<IdentityRedirectManager>(); builder.Services.AddScoped<IdentityRedirectManager>();
builder.Services.AddScoped<AuthenticationStateProvider, IdentityRevalidatingAuthenticationStateProvider>(); builder.Services.AddScoped<AuthenticationStateProvider, IdentityRevalidatingAuthenticationStateProvider>();
// Authentication: primary = Identity cookie
builder.Services.AddAuthentication(options => builder.Services.AddAuthentication(options =>
{ {
options.DefaultScheme = IdentityConstants.ApplicationScheme; options.DefaultScheme = IdentityConstants.ApplicationScheme;
options.DefaultSignInScheme = IdentityConstants.ExternalScheme; options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
// Keep challenge on cookie/login page; Windows is performed explicitly via /auth/windows.
options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
}) })
.AddIdentityCookies(); .AddIdentityCookies();
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found."); // Windows Integrated (Kerberos/NTLM):
// - On IIS / IIS Express: do NOT register AddNegotiate(); IIS handles Windows auth and populates HttpContext.User.
// - Outside IIS: you may register AddNegotiate() (optional), but typical intranet hosting uses IIS anyway.
if (windowsEnabled && !runningUnderIis)
{
builder.Services.AddAuthentication()
.AddNegotiate();
}
builder.Services.AddAuthorization();
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection")
?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options => builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString)); options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter(); builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddIdentityCore<ApplicationUser>(options => builder.Services.AddIdentityCore<ApplicationUser>(options =>
{ {
options.SignIn.RequireConfirmedAccount = true; // Email confirmation disabled for now (can be enabled later)
options.SignIn.RequireConfirmedAccount = false;
options.Stores.SchemaVersion = IdentitySchemaVersions.Version3; options.Stores.SchemaVersion = IdentitySchemaVersions.Version3;
}) })
.AddEntityFrameworkStores<ApplicationDbContext>() .AddEntityFrameworkStores<ApplicationDbContext>()
@@ -40,6 +69,13 @@ builder.Services.AddSingleton<IEmailSender<ApplicationUser>, IdentityNoOpEmailSe
var app = builder.Build(); var app = builder.Build();
// Optionally guard against misconfiguration
// (Windows mode is intended for IIS/IIS Express intranet hosting)
if (windowsEnabled && !runningUnderIis)
{
app.Logger.LogWarning("Auth:Mode=Windows but the app is not running under IIS/IIS Express. Windows Integrated auth may not work as expected.");
}
// Configure the HTTP request pipeline. // Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment()) if (app.Environment.IsDevelopment())
{ {
@@ -48,14 +84,85 @@ if (app.Environment.IsDevelopment())
else else
{ {
app.UseExceptionHandler("/Error", createScopeForErrors: true); app.UseExceptionHandler("/Error", createScopeForErrors: true);
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts(); app.UseHsts();
} }
app.UseStatusCodePagesWithReExecute("/not-found", createScopeForStatusCodePages: true);
app.UseStatusCodePagesWithReExecute("/not-found");
app.UseHttpsRedirection(); app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
if (windowsEnabled)
{
app.Use(async (context, next) =>
{
// Pokud už je pøihlášený (cookie), nech vše projít.
if (context.User?.Identity?.IsAuthenticated == true)
{
await next();
return;
}
var path = context.Request.Path;
// Nikdy neredirectovat:
// - bootstrap endpoint
// - identity stránky/endpoints
// - chybové stránky
// - blazor framework a static web assets
if (path.StartsWithSegments("/auth/windows") ||
path.StartsWithSegments("/Account") ||
path.StartsWithSegments("/not-found") ||
path.StartsWithSegments("/Error") ||
path.StartsWithSegments("/_framework") ||
path.StartsWithSegments("/_content"))
{
await next();
return;
}
// Nezasahovat do statických souborù podle pøípony (CSS/JS/fonts/images/maps)
var ext = System.IO.Path.GetExtension(path);
if (!string.IsNullOrEmpty(ext))
{
await next();
return;
}
// Redirect jen pro "navigaèní" requesty (typicky HTML stránky)
if (!HttpMethods.IsGet(context.Request.Method))
{
await next();
return;
}
// Pokud klient nechce HTML (napø. fetch pro JSON), neredirectuj
var accept = context.Request.Headers.Accept.ToString();
if (!string.IsNullOrEmpty(accept) && !accept.Contains("text/html", StringComparison.OrdinalIgnoreCase))
{
await next();
return;
}
var returnUrl = context.Request.PathBase + context.Request.Path + context.Request.QueryString;
var target = "/auth/windows?returnUrl=" + Uri.EscapeDataString(returnUrl);
context.Response.Redirect(target);
});
}
app.UseAuthorization();
app.UseAntiforgery(); app.UseAntiforgery();
app.MapStaticAssets(); app.MapStaticAssets();
app.MapRazorComponents<App>() app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode(); .AddInteractiveServerRenderMode();

View File

@@ -1,23 +1,40 @@
{ {
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": { "profiles": {
"http": { "IIS Express": {
"commandName": "Project", "commandName": "IISExpress",
"dotnetRunMessages": true,
"launchBrowser": true, "launchBrowser": true,
"applicationUrl": "http://localhost:5250",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} },
"windowsAuthentication": true,
"anonymousAuthentication": false
}, },
"https": { "https": {
"commandName": "Project", "commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true, "launchBrowser": true,
"applicationUrl": "https://localhost:7229;http://localhost:5250",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} },
"dotnetRunMessages": true,
"applicationUrl": "https://localhost:7229;http://localhost:5250"
},
"http": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true,
"applicationUrl": "http://localhost:5250"
}
},
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:53505/",
"sslPort": 44361
} }
} }
} }

View File

@@ -9,6 +9,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.Negotiate" Version="10.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="10.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="10.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.3" /> <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.3" />

View File

@@ -1,6 +1,6 @@
{ {
"ConnectionStrings": { "ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-RIIT-d783c396-a1d0-4ecc-bb0a-5fec040e8d36;Trusted_Connection=True;MultipleActiveResultSets=true" "DefaultConnection": "Server=localhost\\SQLEXPRESS;Database=RIIT;Integrated Security=SSPI;TrustServerCertificate=True;"
}, },
"Logging": { "Logging": {
"LogLevel": { "LogLevel": {
@@ -8,5 +8,11 @@
"Microsoft.AspNetCore": "Warning" "Microsoft.AspNetCore": "Warning"
} }
}, },
"Auth": {
"Mode": "Windows",
"Windows": {
"RequireAuthenticatedUser": true
}
},
"AllowedHosts": "*" "AllowedHosts": "*"
} }