From de8d363c27a61a48c4a64b12e0ee1f984575d665 Mon Sep 17 00:00:00 2001 From: TekH Date: Sun, 31 May 2026 09:01:02 +0200 Subject: [PATCH] Add authentication for secure document access Introduced a new login page (`Login.razor`) to handle user authentication via access codes. Implemented `AuthService` to validate access codes through an API. Updated `ReportViewer.razor` to check user access and redirect unauthorized users to the login page. Modified `Program.cs` to register `AuthService` for dependency injection. Enhanced document fetching in `ReportViewer.razor` to ensure secure access control. --- .../Pages/Login.razor | 71 +++++++++++++++++++ .../Pages/ReportViewer.razor | 10 +++ EnvelopeGenerator.ReceiverUI/Program.cs | 1 + .../Services/AuthService.cs | 20 ++++++ 4 files changed, 102 insertions(+) create mode 100644 EnvelopeGenerator.ReceiverUI/Pages/Login.razor create mode 100644 EnvelopeGenerator.ReceiverUI/Services/AuthService.cs diff --git a/EnvelopeGenerator.ReceiverUI/Pages/Login.razor b/EnvelopeGenerator.ReceiverUI/Pages/Login.razor new file mode 100644 index 00000000..269e2250 --- /dev/null +++ b/EnvelopeGenerator.ReceiverUI/Pages/Login.razor @@ -0,0 +1,71 @@ +@page "/login/{EnvelopeKey}" +@using EnvelopeGenerator.ReceiverUI.Options +@using Microsoft.Extensions.Options + +
+
+
+ +

Zugang zum Dokument

+

+ Bitte geben Sie den Zugangscode ein, den Sie per E-Mail erhalten haben, um das Dokument zu öffnen. +

+ + @if (!string.IsNullOrWhiteSpace(ErrorMessage)) { +
@ErrorMessage
+ } + +
+ + +
+ + + +
+
+
+ +@code { + [Parameter] public string EnvelopeKey { get; set; } = string.Empty; + + string AccessCode = string.Empty; + string? ErrorMessage; + bool IsLoading; + + async Task OnKeyDownAsync(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs e) { + if (e.Key == "Enter") + await SubmitAsync(); + } + + async Task SubmitAsync() { + if (string.IsNullOrWhiteSpace(AccessCode)) return; + + IsLoading = true; + ErrorMessage = null; + await InvokeAsync(StateHasChanged); + + // TODO: API entegrasyonu buraya eklenecek + await Task.Delay(500); // placeholder + + IsLoading = false; + ErrorMessage = "Der eingegebene Zugangscode ist ungültig. Bitte versuchen Sie es erneut."; + await InvokeAsync(StateHasChanged); + } +} diff --git a/EnvelopeGenerator.ReceiverUI/Pages/ReportViewer.razor b/EnvelopeGenerator.ReceiverUI/Pages/ReportViewer.razor index aae71118..c09740c0 100644 --- a/EnvelopeGenerator.ReceiverUI/Pages/ReportViewer.razor +++ b/EnvelopeGenerator.ReceiverUI/Pages/ReportViewer.razor @@ -19,8 +19,10 @@ @using EnvelopeGenerator.ReceiverUI.Options @inject IJSRuntime JSRuntime @inject IOptions AppOptions +@inject NavigationManager Navigation @inject InMemoryReportStorageWebExtension ReportStorage @inject EnvelopeGenerator.ReceiverUI.Services.DocumentService DocumentService +@inject EnvelopeGenerator.ReceiverUI.Services.AuthService AuthService @@ -170,6 +172,14 @@ protected override async Task OnInitializedAsync() { + if (!string.IsNullOrWhiteSpace(EnvelopeKey)) { + var hasAccess = await AuthService.CheckEnvelopeAccessAsync(EnvelopeKey); + if (!hasAccess) { + Navigation.NavigateTo($"/login/{Uri.EscapeDataString(EnvelopeKey)}"); + return; + } + } + if (!AppOptions.Value.ForceToUseFakeDocument && !string.IsNullOrWhiteSpace(EnvelopeKey)) { var (pdfBytes, _) = await DocumentService.GetDocumentAsync(EnvelopeKey); if (pdfBytes is { Length: > 0 }) { diff --git a/EnvelopeGenerator.ReceiverUI/Program.cs b/EnvelopeGenerator.ReceiverUI/Program.cs index 369d98fc..00b87dd5 100644 --- a/EnvelopeGenerator.ReceiverUI/Program.cs +++ b/EnvelopeGenerator.ReceiverUI/Program.cs @@ -15,6 +15,7 @@ builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder. builder.Services.Configure(opts => builder.Configuration.GetSection(ApiOptions.SectionName).Bind(opts)); builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddDevExpressWebAssemblyBlazorReportViewer(); builder.Services.AddDevExpressWebAssemblyBlazorPdfViewer(); diff --git a/EnvelopeGenerator.ReceiverUI/Services/AuthService.cs b/EnvelopeGenerator.ReceiverUI/Services/AuthService.cs new file mode 100644 index 00000000..6cb8ca18 --- /dev/null +++ b/EnvelopeGenerator.ReceiverUI/Services/AuthService.cs @@ -0,0 +1,20 @@ +using System.Net; +using EnvelopeGenerator.ReceiverUI.Options; +using Microsoft.Extensions.Options; + +namespace EnvelopeGenerator.ReceiverUI.Services; + +public class AuthService(HttpClient http, IOptions apiOptions) +{ + private readonly ApiOptions _api = apiOptions.Value; + + /// + /// Checks whether the current user holds a valid receiver token for the given envelope key. + /// Calls GET /api/auth/check/envelope/{envelopeKey}. + /// + public async Task CheckEnvelopeAccessAsync(string envelopeKey, CancellationToken cancel = default) + { + var response = await http.GetAsync($"{_api.BaseUrl}/api/auth/check/envelope/{Uri.EscapeDataString(envelopeKey)}", cancel); + return response.StatusCode == HttpStatusCode.OK; + } +}