lokale Authentifizierung mit Standard-User admin+changeme
This commit is contained in:
@@ -1,16 +1,61 @@
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Watcher.Data;
|
||||
using Watcher.ViewModels;
|
||||
|
||||
namespace Watcher.Controllers;
|
||||
|
||||
public class AuthController : Controller
|
||||
{
|
||||
public IActionResult Login()
|
||||
private readonly AppDbContext _context;
|
||||
|
||||
public AuthController(AppDbContext context)
|
||||
{
|
||||
return View();
|
||||
_context = context;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult Login(string? returnUrl = null)
|
||||
{
|
||||
var model = new LoginViewModel
|
||||
{
|
||||
ReturnUrl = returnUrl
|
||||
};
|
||||
return View(model);
|
||||
}
|
||||
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Login(LoginViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
return View(model);
|
||||
|
||||
var user = await _context.Users.FirstOrDefaultAsync(u => u.PreferredUsername == model.Username);
|
||||
if (user == null || !BCrypt.Net.BCrypt.Verify(model.Password, user.Password))
|
||||
{
|
||||
ModelState.AddModelError("", "Benutzername oder Passwort ist falsch.");
|
||||
return View(model);
|
||||
}
|
||||
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new Claim(ClaimTypes.Name, user.PreferredUsername),
|
||||
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
|
||||
};
|
||||
|
||||
var identity = new ClaimsIdentity(claims, "local");
|
||||
var principal = new ClaimsPrincipal(identity);
|
||||
|
||||
await HttpContext.SignInAsync("Cookies", principal);
|
||||
|
||||
return Redirect("Home/Index");
|
||||
}
|
||||
|
||||
|
||||
public IActionResult SignIn()
|
||||
{
|
||||
return Challenge(new AuthenticationProperties
|
||||
@@ -20,20 +65,20 @@ public class AuthController : Controller
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Logout()
|
||||
{
|
||||
// Lokales Cookie löschen
|
||||
await HttpContext.SignOutAsync("Cookies");
|
||||
|
||||
// Externes OIDC-Logout initiieren
|
||||
await HttpContext.SignOutAsync("oidc", new AuthenticationProperties
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Logout()
|
||||
{
|
||||
RedirectUri = "/" // Nach Logout zurück zur Startseite oder Login-Seite
|
||||
});
|
||||
var props = new AuthenticationProperties
|
||||
{
|
||||
RedirectUri = Url.Action("Login", "Auth")
|
||||
};
|
||||
|
||||
await HttpContext.SignOutAsync("Cookies");
|
||||
await HttpContext.SignOutAsync("oidc", props);
|
||||
|
||||
return Redirect("/"); // nur als Fallback
|
||||
}
|
||||
|
||||
return RedirectToAction("Index", "Home");
|
||||
}
|
||||
|
||||
[Authorize]
|
||||
public IActionResult Info()
|
||||
@@ -46,4 +91,46 @@ public async Task<IActionResult> Logout()
|
||||
|
||||
return View();
|
||||
}
|
||||
|
||||
// Edit-Form anzeigen
|
||||
[Authorize]
|
||||
[HttpGet]
|
||||
public IActionResult Edit()
|
||||
{
|
||||
var username = User.Identity?.Name;
|
||||
var user = _context.Users.FirstOrDefault(u => u.PreferredUsername == username);
|
||||
if (user == null) return NotFound();
|
||||
|
||||
var model = new EditUserViewModel
|
||||
{
|
||||
Username = user.PreferredUsername
|
||||
};
|
||||
return View(model);
|
||||
}
|
||||
|
||||
// Edit speichern
|
||||
[Authorize]
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public IActionResult Edit(EditUserViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid) return View(model);
|
||||
|
||||
var username = User.Identity?.Name;
|
||||
var user = _context.Users.FirstOrDefault(u => u.PreferredUsername == username);
|
||||
if (user == null) return NotFound();
|
||||
|
||||
user.PreferredUsername = model.Username;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(model.NewPassword))
|
||||
{
|
||||
user.PreferredUsername = BCrypt.Net.BCrypt.HashPassword(model.NewPassword);
|
||||
}
|
||||
|
||||
_context.SaveChanges();
|
||||
|
||||
// Eventuell hier das Auth-Cookie erneuern, wenn Username sich ändert
|
||||
|
||||
return RedirectToAction("Index", "Home");
|
||||
}
|
||||
}
|
||||
|
@@ -7,7 +7,7 @@ using Watcher.ViewModels;
|
||||
|
||||
namespace Watcher.Controllers;
|
||||
|
||||
|
||||
[Authorize]
|
||||
public class ContainerController : Controller
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
|
306
Watcher/Migrations/20250617174242_UserPasswordAdded.Designer.cs
generated
Normal file
306
Watcher/Migrations/20250617174242_UserPasswordAdded.Designer.cs
generated
Normal file
@@ -0,0 +1,306 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Watcher.Data;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Watcher.Migrations
|
||||
{
|
||||
[DbContext(typeof(AppDbContext))]
|
||||
[Migration("20250617174242_UserPasswordAdded")]
|
||||
partial class UserPasswordAdded
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "8.0.6");
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.Container", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Hostname")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("ImageId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("IsRunning")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("TagId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ImageId");
|
||||
|
||||
b.HasIndex("TagId");
|
||||
|
||||
b.ToTable("Containers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.Image", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Tag")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Images");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.LogEvent", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("ContainerId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Level")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Message")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("ServerId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("Timestamp")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ContainerId");
|
||||
|
||||
b.HasIndex("ServerId");
|
||||
|
||||
b.ToTable("LogEvents");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.Metric", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("ContainerId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("ServerId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("Timestamp")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<double>("Value")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ContainerId");
|
||||
|
||||
b.HasIndex("ServerId");
|
||||
|
||||
b.ToTable("Metrics");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.Server", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("CpuCores")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("CpuType")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("GpuType")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("IPAddress")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsOnline")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("LastSeen")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<double>("RamSize")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<int?>("TagId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("TagId");
|
||||
|
||||
b.ToTable("Servers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.Tag", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Tags");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("IdentityProvider")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("LastLogin")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Password")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PocketId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PreferredUsername")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.Container", b =>
|
||||
{
|
||||
b.HasOne("Watcher.Models.Image", "Image")
|
||||
.WithMany("Containers")
|
||||
.HasForeignKey("ImageId");
|
||||
|
||||
b.HasOne("Watcher.Models.Tag", null)
|
||||
.WithMany("Containers")
|
||||
.HasForeignKey("TagId");
|
||||
|
||||
b.Navigation("Image");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.LogEvent", b =>
|
||||
{
|
||||
b.HasOne("Watcher.Models.Container", "Container")
|
||||
.WithMany()
|
||||
.HasForeignKey("ContainerId");
|
||||
|
||||
b.HasOne("Watcher.Models.Server", "Server")
|
||||
.WithMany()
|
||||
.HasForeignKey("ServerId");
|
||||
|
||||
b.Navigation("Container");
|
||||
|
||||
b.Navigation("Server");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.Metric", b =>
|
||||
{
|
||||
b.HasOne("Watcher.Models.Container", "Container")
|
||||
.WithMany()
|
||||
.HasForeignKey("ContainerId");
|
||||
|
||||
b.HasOne("Watcher.Models.Server", "Server")
|
||||
.WithMany()
|
||||
.HasForeignKey("ServerId");
|
||||
|
||||
b.Navigation("Container");
|
||||
|
||||
b.Navigation("Server");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.Server", b =>
|
||||
{
|
||||
b.HasOne("Watcher.Models.Tag", null)
|
||||
.WithMany("Servers")
|
||||
.HasForeignKey("TagId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.Image", b =>
|
||||
{
|
||||
b.Navigation("Containers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.Tag", b =>
|
||||
{
|
||||
b.Navigation("Containers");
|
||||
|
||||
b.Navigation("Servers");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
40
Watcher/Migrations/20250617174242_UserPasswordAdded.cs
Normal file
40
Watcher/Migrations/20250617174242_UserPasswordAdded.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Watcher.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class UserPasswordAdded : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "IdentityProvider",
|
||||
table: "Users",
|
||||
type: "TEXT",
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Password",
|
||||
table: "Users",
|
||||
type: "TEXT",
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "IdentityProvider",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Password",
|
||||
table: "Users");
|
||||
}
|
||||
}
|
||||
}
|
@@ -212,9 +212,17 @@ namespace Watcher.Migrations
|
||||
b.Property<string>("Email")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("IdentityProvider")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("LastLogin")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Password")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PocketId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
@@ -1,3 +1,5 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Watcher.Models;
|
||||
|
||||
public class User
|
||||
@@ -7,4 +9,11 @@ public class User
|
||||
public string PreferredUsername { get; set; } = null!;
|
||||
public string? Email { get; set; }
|
||||
public DateTime LastLogin { get; set; }
|
||||
|
||||
[Required]
|
||||
public string IdentityProvider { get; set; } = "local";
|
||||
|
||||
[Required]
|
||||
[DataType(DataType.Password)]
|
||||
public String? Password { get; set; } = string.Empty;
|
||||
}
|
||||
|
@@ -59,7 +59,7 @@ builder.Services.AddAuthentication(options =>
|
||||
})
|
||||
.AddCookie("Cookies", options =>
|
||||
{
|
||||
options.LoginPath = "/Account/Login"; // Falls eigene Login-Seite
|
||||
options.LoginPath = "/Auth/Login";
|
||||
});
|
||||
|
||||
// PocketID nur konfigurieren, wenn aktiviert
|
||||
@@ -108,7 +108,9 @@ if (pocketIdEnabled)
|
||||
PocketId = pocketId,
|
||||
PreferredUsername = preferredUsername ?? "",
|
||||
Email = email,
|
||||
LastLogin = DateTime.UtcNow
|
||||
LastLogin = DateTime.UtcNow,
|
||||
IdentityProvider = "oidc",
|
||||
Password = string.Empty
|
||||
};
|
||||
db.Users.Add(user);
|
||||
}
|
||||
@@ -130,6 +132,47 @@ if (pocketIdEnabled)
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
|
||||
|
||||
// Migrationen anwenden (für SQLite oder andere DBs)
|
||||
using (var scope = app.Services.CreateScope())
|
||||
{
|
||||
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
db.Database.Migrate();
|
||||
}
|
||||
|
||||
|
||||
// Standart-User in Datenbank schreiben
|
||||
using (var scope = app.Services.CreateScope())
|
||||
{
|
||||
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
Console.WriteLine("Checking for users...");
|
||||
|
||||
if (!db.Users.Any())
|
||||
{
|
||||
Console.WriteLine("No users found, creating default user...");
|
||||
|
||||
var defaultUser = new User
|
||||
{
|
||||
PocketId = string.Empty,
|
||||
PreferredUsername = "admin",
|
||||
Email = string.Empty,
|
||||
LastLogin = DateTime.UtcNow,
|
||||
IdentityProvider = "local",
|
||||
Password = BCrypt.Net.BCrypt.HashPassword("changeme")
|
||||
};
|
||||
db.Users.Add(defaultUser);
|
||||
db.SaveChanges();
|
||||
|
||||
Console.WriteLine("Default user created.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Users already exist.");
|
||||
}
|
||||
}
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (!app.Environment.IsDevelopment())
|
||||
{
|
||||
@@ -138,12 +181,10 @@ if (!app.Environment.IsDevelopment())
|
||||
app.UseHsts();
|
||||
}
|
||||
|
||||
// Migrationen anwenden (für SQLite oder andere DBs)
|
||||
using (var scope = app.Services.CreateScope())
|
||||
{
|
||||
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
db.Database.Migrate();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
app.UseRouting();
|
||||
|
18
Watcher/ViewModels/EditUserViewModel.cs
Normal file
18
Watcher/ViewModels/EditUserViewModel.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Watcher.ViewModels;
|
||||
|
||||
public class EditUserViewModel
|
||||
{
|
||||
[Required]
|
||||
public string? Username { get; set; }
|
||||
|
||||
[Required]
|
||||
[DataType(DataType.Password)]
|
||||
public string? NewPassword { get; set; }
|
||||
|
||||
[Required]
|
||||
[DataType(DataType.Password)]
|
||||
[Compare("NewPassword", ErrorMessage = "Passwörter stimmen nicht überein.")]
|
||||
public string? ConfirmPassword { get; set; }
|
||||
}
|
0
Watcher/Views/Auth/EditUser.cshtml
Normal file
0
Watcher/Views/Auth/EditUser.cshtml
Normal file
@@ -76,11 +76,29 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@{
|
||||
|
||||
<h3>Alle Claims</h3>
|
||||
<ul>
|
||||
@foreach (var claim in User.Claims)
|
||||
{
|
||||
<li>@claim.Type: @claim.Value</li>
|
||||
}
|
||||
</ul>
|
||||
@if (User.Identity.Name == "admin")
|
||||
{
|
||||
<h3>Benutzerdaten ändern</h3>
|
||||
<form asp-action="Edit" method="post" asp-controller="Auth">
|
||||
<div class="mb-3">
|
||||
<label for="Username" class="form-label">Username</label>
|
||||
<input type="text" class="form-control" id="Username" name="Username" value="@User.Identity?.Name" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="NewPassword" class="form-label">Neues Passwort</label>
|
||||
<input type="password" class="form-control" id="NewPassword" name="NewPassword" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="ConfirmPassword" class="form-label">Passwort bestätigen</label>
|
||||
<input type="password" class="form-control" id="ConfirmPassword" name="ConfirmPassword" />
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Speichern</button>
|
||||
</form>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p>Benutzerdaten können nur für lokal angemeldete Nutzer geändert werden.</p>
|
||||
}
|
||||
|
@@ -6,7 +6,9 @@
|
||||
<div class="login-container">
|
||||
<h2>Login</h2>
|
||||
|
||||
<form asp-action="Login" method="post">
|
||||
<form asp-controller="Auth" asp-action="Login" method="post">
|
||||
<input type="hidden" asp-for="ReturnUrl" />
|
||||
|
||||
<div>
|
||||
<label asp-for="Username"></label>
|
||||
<input asp-for="Username" />
|
||||
|
@@ -8,6 +8,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<!-- EF Core Design Tools -->
|
||||
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
||||
<PackageReference Include="DotNetEnv" Version="3.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.4" />
|
||||
|
Reference in New Issue
Block a user