diff options
| -rw-r--r-- | Controllers/LoginController.cs | 41 | ||||
| -rw-r--r-- | Pages/Component/Titlebar.razor | 115 | ||||
| -rw-r--r-- | Pages/Gallery.razor | 1 | ||||
| -rw-r--r-- | Pages/TagDefinitions.razor | 1 | ||||
| -rw-r--r-- | Pages/Upload.razor | 1 | ||||
| -rw-r--r-- | Pages/ViewMedia.razor | 2 | ||||
| -rw-r--r-- | Program.cs | 4 | ||||
| -rw-r--r-- | Properties/launchSettings.json | 1 | ||||
| -rw-r--r-- | Services/GlobalUserService.cs | 7 | ||||
| -rw-r--r-- | Services/UserService.cs | 48 |
10 files changed, 117 insertions, 104 deletions
diff --git a/Controllers/LoginController.cs b/Controllers/LoginController.cs new file mode 100644 index 0000000..fff3e6e --- /dev/null +++ b/Controllers/LoginController.cs @@ -0,0 +1,41 @@ +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Mvc; +using System.Security.Claims; + +namespace HyperBooru.Controllers; + +[ApiController] +[Route("/")] +public class LoginController : Controller { + private IHttpContextAccessor httpContextAccessor; + public LoginController(IHttpContextAccessor httpContextAccessor) => + this.httpContextAccessor = httpContextAccessor; + + [HttpPost("Login")] + public async Task<IActionResult> Login( + [FromForm] string username, + [FromForm] string password) { + + var claims = new Claim[] { + new Claim(ClaimTypes.NameIdentifier, username) + }; + + var claimsIdentity = new ClaimsIdentity( + claims, + CookieAuthenticationDefaults.AuthenticationScheme); + + var claimsPrincipal = new ClaimsPrincipal(claimsIdentity); + + if(username == "admin" && password == "test") { + await httpContextAccessor.HttpContext!.SignInAsync(claimsPrincipal); + return Ok(); + } else { + return StatusCode(403); + } + } + + [HttpPost("Logout")] + public async Task Logout() => + await httpContextAccessor.HttpContext!.SignOutAsync(); +} diff --git a/Pages/Component/Titlebar.razor b/Pages/Component/Titlebar.razor index 71f3bd0..bcd5f61 100644 --- a/Pages/Component/Titlebar.razor +++ b/Pages/Component/Titlebar.razor @@ -1,64 +1,83 @@ @inject IUserService userService @inject NavigationManager navigationManager @inject IJSRuntime jsRuntime +@inject AuthenticationStateProvider authStateProvider -@if(authorized) { - <div id="navbar"> - <a href="/">Home</a> - <a href="/TagDefinitions">Tags</a> - <a href="/Gallery?ingest=true">Ingest</a> - <a href="/Upload">Upload</a> - <a href="javascript:;" @onclick=@(() => aboutDialog.Show())>About</a> +<script suppress-error="BL9992"> + async function login() { + var username = document.querySelector('input#username'); + var password = document.querySelector('input#password'); - <p id="nsfw-label">NSFW</p> - <div id="nsfw-switch"> - <NsfwSwitch/> - </div> - <form action="/Gallery" method="get"> - <input type="text" name="q" placeholder="Search"/> - </form> - <a href="javascript:;" @onclick=userService.Logout>Logout</a> - </div> - <AboutDialog @ref=aboutDialog/> -} else { - <div id="navbar"> - <h2>Login</h2> - <form @onsubmit=Login class="login"> - <input @bind=username name="username" placeholder="Username" type="text"/> - <input @bind=password name="password" placeholder="Password" type="password"/> - </form> - <a href="javascript:;" @onclick=Login>Login</a> - <a href="javascript:;" @onclick=userService.Logout>Logout</a> - </div> - <script suppress-error="BL9992"> - function warnBadLogin() { + var formData = new FormData(); + formData.append('username', username.value); + formData.append('password', password.value); + + var resp = await fetch('/Login', { + method: 'POST', + body: formData + }); + + if(resp.ok) { + if(document.referrer) { + window.location.href = document.referrer; + } else { + window.location.href = '/'; + } + } else if(resp.status == 403) { var form = document.querySelector('form.login'); form.classList.remove('bad-login'); @* TODO: improve this hacky method of triggering reflow *@ form.offsetWidth; form.classList.add('bad-login'); - document.querySelector('form.login input').focus(); + username.value = password.value = null; + username.focus(); + } else { + alert('Unknown error while attempting to login!'); } - </script> -} - -@code { - private bool authorized = false; + } - private string username; - private string password; + async function logout() { + var resp = await fetch('/Logout', { method: 'POST' }); + if(resp.ok) { + window.location.href = '/Login'; + } else { + alert('Error logging out!'); + } + } +</script> - private AboutDialog aboutDialog; +<AuthorizeView> + <Authorized> + <div id="navbar"> + <a href="/">Home</a> + <a href="/TagDefinitions">Tags</a> + <a href="/Gallery?ingest=true">Ingest</a> + <a href="/Upload">Upload</a> + <a href="javascript:;" @onclick=@(() => aboutDialog.Show())>About</a> - private void Login() { - if(userService.Login(username, password)) - navigationManager.NavigateTo("/"); - else - WarnBadLogin(); - } + <p id="nsfw-label">NSFW</p> + <div id="nsfw-switch"> + <NsfwSwitch/> + </div> + <form action="/Gallery" method="get"> + <input type="text" name="q" placeholder="Search"/> + </form> + <a href="javascript:logout();">Logout</a> + </div> + <AboutDialog @ref=aboutDialog/> + </Authorized> + <NotAuthorized> + <div id="navbar"> + <h2>Login</h2> + <form onsubmit="login" class="login"> + <input id="username" placeholder="Username" type="text"/> + <input id="password" placeholder="Password" type="password"/> + </form> + <a href="javascript:login();">Login</a> + </div> + </NotAuthorized> +</AuthorizeView> - private void WarnBadLogin() { - jsRuntime.InvokeVoidAsync("warnBadLogin"); - username = password = ""; - } +@code { + private AboutDialog aboutDialog; } diff --git a/Pages/Gallery.razor b/Pages/Gallery.razor index 7e183f2..d473c28 100644 --- a/Pages/Gallery.razor +++ b/Pages/Gallery.razor @@ -6,6 +6,7 @@ @inject IUserService userService @inject IJSRuntime jsRuntime @implements IDisposable +@attribute [Authorize] <PageTitle>@Title</PageTitle> diff --git a/Pages/TagDefinitions.razor b/Pages/TagDefinitions.razor index 1a29b40..f728631 100644 --- a/Pages/TagDefinitions.razor +++ b/Pages/TagDefinitions.razor @@ -3,6 +3,7 @@ @inject ITagService tagService @inject IUserService userService @implements IDisposable +@attribute [Authorize] <PageTitle>Tag Definitions</PageTitle> diff --git a/Pages/Upload.razor b/Pages/Upload.razor index 7f7980b..614cec0 100644 --- a/Pages/Upload.razor +++ b/Pages/Upload.razor @@ -1,4 +1,5 @@ @page "/Upload" +@attribute [Authorize] <div id="dropzone"> <p>Drag a file to upload it<br/>or click to select one or more file(s)</p> diff --git a/Pages/ViewMedia.razor b/Pages/ViewMedia.razor index 1b6f959..444fbc5 100644 --- a/Pages/ViewMedia.razor +++ b/Pages/ViewMedia.razor @@ -4,7 +4,7 @@ @inject IDbContextFactory<HBContext> dbFactory @inject ITagService tagService @inject IMediaService mediaService -@*@attribute [Authorize]*@ +@attribute [Authorize] <PageTitle>@title</PageTitle> @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore; using System.Text.Json.Serialization; using HyperBooru.Services; +using Microsoft.AspNetCore.Authentication.Cookies; namespace HyperBooru; @@ -9,6 +10,8 @@ public class Program { var builder = WebApplication.CreateBuilder(args); builder.Services.AddAuthentication().AddCookie(); builder.Services.AddHttpContextAccessor(); + builder.Services.AddAuthentication( + CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(); builder.Services.AddControllers().AddJsonOptions(o => { var converter = new JsonStringEnumConverter(); o.JsonSerializerOptions.Converters.Add(converter); @@ -22,7 +25,6 @@ public class Program { builder.Services.AddScoped<ISearchService, SearchService>(); builder.Services.AddScoped<ITagService, TagService>(); builder.Services.AddScoped<IMediaService, MediaService>(); - builder.Services.AddSingleton<IGlobalUserService, GlobalUserService>(); builder.Services.AddScoped<IUserService, UserService>(); builder.Services.AddHostedService<OcrService>(); diff --git a/Properties/launchSettings.json b/Properties/launchSettings.json index 9f4966c..b1659dc 100644 --- a/Properties/launchSettings.json +++ b/Properties/launchSettings.json @@ -13,6 +13,7 @@ "HyperBooru": { "commandName": "Project", "launchBrowser": true, + "launchUrl": "Login", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, diff --git a/Services/GlobalUserService.cs b/Services/GlobalUserService.cs deleted file mode 100644 index adafce2..0000000 --- a/Services/GlobalUserService.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace HyperBooru.Services; - -public interface IGlobalUserService { -} - -public class GlobalUserService : IGlobalUserService { -} diff --git a/Services/UserService.cs b/Services/UserService.cs index 96f5b5f..d2abea3 100644 --- a/Services/UserService.cs +++ b/Services/UserService.cs @@ -1,18 +1,9 @@ -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Authentication.Cookies; -using System.Runtime.InteropServices; -using System.Security.Claims; -using System.Security.Principal; - -namespace HyperBooru.Services; +namespace HyperBooru.Services; public interface IUserService { public bool ShowNsfw { get; set; } public event EventHandler<bool> ShowNsfwChanged; - - public bool Login(string username, string password); - public void Logout(); } public class UserService : IUserService { @@ -27,41 +18,4 @@ public class UserService : IUserService { public event EventHandler<bool> ShowNsfwChanged; private bool showNsfw = false; - - private IGlobalUserService globalUserService; - private IHttpContextAccessor httpContextAccessor; - - public UserService( - IGlobalUserService globalUserService, - IHttpContextAccessor httpContextAccessor) { - - this.globalUserService = globalUserService; - this.httpContextAccessor = httpContextAccessor; - } - - public bool Login(string username, string password) { - var claims = new Claim[] { - }; - - var claimsIdentity = new ClaimsIdentity( - claims, - CookieAuthenticationDefaults.AuthenticationScheme); - - var claimsPrincipal = new ClaimsPrincipal(claimsIdentity); - - if(httpContextAccessor.HttpContext is null) - return false; - - httpContextAccessor.HttpContext.SignInAsync(claimsPrincipal) - .GetAwaiter() - .GetResult(); - - return true; - } - - public void Logout() { - httpContextAccessor.HttpContext?.SignOutAsync() - .GetAwaiter() - .GetResult(); - } } |
