Created first time setup to create initial admin account
parent
a0d7134af3
commit
5bcf8d3e3c
|
@ -0,0 +1,52 @@
|
|||
@page
|
||||
@model FirstTimeSetupModel
|
||||
@{
|
||||
Layout = "/Views/Shared/_LayoutBasic.cshtml";
|
||||
}
|
||||
@{
|
||||
ViewData["Title"] = "First Time Setup";
|
||||
}
|
||||
|
||||
<div class="page page-center">
|
||||
<form asp-route-returnUrl="@Model.ReturnUrl" class="container-tight py-4">
|
||||
<div class="text-center mb-4">
|
||||
<h2>LANCommander</h2>
|
||||
</div>
|
||||
<div class="card card-md">
|
||||
<div class="card-body text-center py-4 p-sm-5">
|
||||
<h1>Welcome to LANCommander!</h1>
|
||||
<p class="text-muted">LANCommander is your one stop shop for distributing games on your LAN. Start your adventure with LANCommander and take control of your local multiplayer gaming!</p>
|
||||
</div>
|
||||
<div class="hr-text hr-text-center hr-text-spaceless">registration</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Register your admin account</label>
|
||||
<input asp-for="Input.UserName" type="text" class="form-control ps-1" autocomplete="off" placeholder="Username" />
|
||||
<div class="form-hint">For first-time setup, an admin user is required. This user will be able to manage all aspects of the application.</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label asp-for="Input.Password" class="form-label"></label>
|
||||
<input asp-for="Input.Password" type="password" class="form-control ps-1" autocomplete="new-password" />
|
||||
<span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label asp-for="Input.ConfirmPassword" class="form-label"></label>
|
||||
<input asp-for="Input.ConfirmPassword" type="password" class="form-control ps-1" autocomplete="new-password" />
|
||||
<span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row align-items-center mt-3">
|
||||
<div class="col">
|
||||
<div class="btn-list justify-content-end">
|
||||
<button type="submit" class="btn btn-primary">Continue</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
<partial name="_ValidationScriptsPartial" />
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using LANCommander.Data.Models;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LANCommander.Areas.Identity.Pages.Account
|
||||
{
|
||||
public class FirstTimeSetupModel : PageModel
|
||||
{
|
||||
private readonly SignInManager<User> _signInManager;
|
||||
private readonly UserManager<User> _userManager;
|
||||
private readonly RoleManager<Role> _roleManager;
|
||||
private readonly IUserStore<User> _userStore;
|
||||
private readonly IUserEmailStore<User> _emailStore;
|
||||
private readonly ILogger<FirstTimeSetupModel> _logger;
|
||||
private readonly IEmailSender _emailSender;
|
||||
|
||||
public FirstTimeSetupModel(
|
||||
UserManager<User> userManager,
|
||||
IUserStore<User> userStore,
|
||||
SignInManager<User> signInManager,
|
||||
RoleManager<Role> roleManager,
|
||||
ILogger<FirstTimeSetupModel> logger,
|
||||
IEmailSender emailSender)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_userStore = userStore;
|
||||
_signInManager = signInManager;
|
||||
_roleManager = roleManager;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
[BindProperty]
|
||||
public InputModel Input { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public string ReturnUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public IList<AuthenticationScheme> ExternalLogins { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public class InputModel
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
[Required]
|
||||
[Display(Name = "Username")]
|
||||
public string UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
[Required]
|
||||
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Password")]
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Confirm password")]
|
||||
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public async Task<IActionResult> OnGetAsync(string returnUrl = null)
|
||||
{
|
||||
ReturnUrl = returnUrl;
|
||||
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
|
||||
|
||||
var administratorRoleExists = await _roleManager.RoleExistsAsync("Administor");
|
||||
|
||||
if (!administratorRoleExists)
|
||||
await _roleManager.CreateAsync(new Role()
|
||||
{
|
||||
Name = "Administrator"
|
||||
});
|
||||
|
||||
var administrators = await _userManager.GetUsersInRoleAsync("Administrator");
|
||||
|
||||
if (administrators.Count > 0)
|
||||
return RedirectToPage("./Login");
|
||||
|
||||
return Page();
|
||||
}
|
||||
|
||||
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
|
||||
{
|
||||
returnUrl ??= Url.Content("~/");
|
||||
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
|
||||
|
||||
var administrators = await _userManager.GetUsersInRoleAsync("Administrator");
|
||||
|
||||
if (administrators.Count > 0)
|
||||
return RedirectToPage("./Login");
|
||||
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var user = CreateUser();
|
||||
|
||||
await _userStore.SetUserNameAsync(user, Input.UserName, CancellationToken.None);
|
||||
var result = await _userManager.CreateAsync(user, Input.Password);
|
||||
|
||||
await _userManager.AddToRoleAsync(user, "Administrator");
|
||||
|
||||
if (result.Succeeded)
|
||||
{
|
||||
_logger.LogInformation("Administrator created a new account with password.");
|
||||
|
||||
var userId = await _userManager.GetUserIdAsync(user);
|
||||
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
|
||||
var callbackUrl = Url.Page(
|
||||
"/Account/ConfirmEmail",
|
||||
pageHandler: null,
|
||||
values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
|
||||
protocol: Request.Scheme);
|
||||
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
return LocalRedirect(returnUrl);
|
||||
}
|
||||
foreach (var error in result.Errors)
|
||||
{
|
||||
ModelState.AddModelError(string.Empty, error.Description);
|
||||
}
|
||||
}
|
||||
|
||||
// If we got this far, something failed, redisplay form
|
||||
return Page();
|
||||
}
|
||||
|
||||
private User CreateUser()
|
||||
{
|
||||
try
|
||||
{
|
||||
return Activator.CreateInstance<User>();
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new InvalidOperationException($"Can't create an instance of '{nameof(User)}'. " +
|
||||
$"Ensure that '{nameof(User)}' is not an abstract class and has a parameterless constructor, or alternatively " +
|
||||
$"override the register page in /Areas/Identity/Pages/Account/FirstTimeSetupModel.cshtml");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,11 +21,17 @@ namespace LANCommander.Areas.Identity.Pages.Account
|
|||
public class LoginModel : PageModel
|
||||
{
|
||||
private readonly SignInManager<User> _signInManager;
|
||||
private readonly UserManager<User> _userManager;
|
||||
private readonly ILogger<LoginModel> _logger;
|
||||
|
||||
public LoginModel(SignInManager<User> signInManager, ILogger<LoginModel> logger)
|
||||
public LoginModel(
|
||||
SignInManager<User> signInManager,
|
||||
UserManager<User> userManager,
|
||||
ILogger<LoginModel> logger
|
||||
)
|
||||
{
|
||||
_signInManager = signInManager;
|
||||
_userManager = userManager;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
@ -86,7 +92,7 @@ namespace LANCommander.Areas.Identity.Pages.Account
|
|||
public bool RememberMe { get; set; }
|
||||
}
|
||||
|
||||
public async Task OnGetAsync(string returnUrl = null)
|
||||
public async Task<IActionResult> OnGetAsync(string returnUrl = null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ErrorMessage))
|
||||
{
|
||||
|
@ -101,6 +107,15 @@ namespace LANCommander.Areas.Identity.Pages.Account
|
|||
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
|
||||
|
||||
ReturnUrl = returnUrl;
|
||||
|
||||
var administrators = await _userManager.GetUsersInRoleAsync("Administrator");
|
||||
|
||||
if (administrators.Count == 0)
|
||||
{
|
||||
return RedirectToPage("./FirstTimeSetup");
|
||||
}
|
||||
|
||||
return Page();
|
||||
}
|
||||
|
||||
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
|
||||
|
|
|
@ -5,7 +5,7 @@ using Microsoft.EntityFrameworkCore;
|
|||
|
||||
namespace LANCommander.Data
|
||||
{
|
||||
public class DatabaseContext : IdentityDbContext<User, IdentityRole<Guid>, Guid>
|
||||
public class DatabaseContext : IdentityDbContext<User, Role, Guid>
|
||||
{
|
||||
public DatabaseContext(DbContextOptions<DatabaseContext> options)
|
||||
: base(options)
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
using Microsoft.AspNetCore.Identity;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace LANCommander.Data.Models
|
||||
{
|
||||
[Table("Roles")]
|
||||
public class Role : IdentityRole<Guid>
|
||||
{
|
||||
}
|
||||
}
|
|
@ -21,7 +21,9 @@ builder.Services.AddDefaultIdentity<User>((IdentityOptions options) => {
|
|||
options.SignIn.RequireConfirmedAccount = false;
|
||||
options.Password.RequireNonAlphanumeric = false;
|
||||
options.SignIn.RequireConfirmedEmail = false;
|
||||
}).AddEntityFrameworkStores<LANCommander.Data.DatabaseContext>();
|
||||
})
|
||||
.AddRoles<Role>()
|
||||
.AddEntityFrameworkStores<LANCommander.Data.DatabaseContext>();
|
||||
|
||||
builder.Services.AddControllersWithViews();
|
||||
|
||||
|
|
Loading…
Reference in New Issue