Refactor sender page and auth service logic

- Added project reference to `EnvelopeGenerator.Application` in the client project.
- Updated imports and injected services in `EnvelopeSenderPage.razor`.
- Improved null handling for `EnvelopeReceivers` and updated email display logic.
- Replaced `CheckSenderAsync` with `CheckSenderAccessAsync` for authorization.
- Refactored `GetStatusInfo` to use `EnvelopeStatus` enum directly.
- Added `CheckSenderAccessAsync` and `LogoutSenderAsync` methods in `AuthService`.
- Simplified `Logout` logic in `AuthController` to remove redundant checks.
This commit is contained in:
2026-06-25 15:17:57 +02:00
parent 85a0736106
commit b5bb2bbaae
4 changed files with 44 additions and 16 deletions

View File

@@ -29,6 +29,10 @@
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.11" PrivateAssets="all" /> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.11" PrivateAssets="all" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\EnvelopeGenerator.Application\EnvelopeGenerator.Application.csproj" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Update="PredefinedReports\Report.cs"> <Compile Update="PredefinedReports\Report.cs">
<SubType>XtraReport</SubType> <SubType>XtraReport</SubType>

View File

@@ -2,6 +2,7 @@
@attribute [Microsoft.AspNetCore.Authorization.Authorize(Policy = "Sender")] @attribute [Microsoft.AspNetCore.Authorization.Authorize(Policy = "Sender")]
@using System.Text.Json @using System.Text.Json
@using EnvelopeGenerator.Domain.Constants
@using EnvelopeGenerator.Server.Client.Models @using EnvelopeGenerator.Server.Client.Models
@using DevExpress.Blazor @using DevExpress.Blazor
@using EnvelopeGenerator.Server.Client.Services @using EnvelopeGenerator.Server.Client.Services
@@ -10,6 +11,12 @@
@inject NavigationManager Navigation @inject NavigationManager Navigation
@inject IJSRuntime JSRuntime @inject IJSRuntime JSRuntime
@inject AppVersionService AppVersion @inject AppVersionService AppVersion
@using EnvelopeGenerator.Application.Common.Dto
@inject EnvelopeGenerator.Server.Client.Services.EnvelopeService EnvelopeService
@inject EnvelopeGenerator.Server.Client.Services.AuthService AuthService
@inject NavigationManager Navigation
@inject IJSRuntime JSRuntime
@inject AppVersionService AppVersion
<link href="_content/DevExpress.Blazor.Themes/blazing-berry.bs5.min.css" rel="stylesheet" /> <link href="_content/DevExpress.Blazor.Themes/blazing-berry.bs5.min.css" rel="stylesheet" />
<link href="@AppVersion.GetVersionedUrl("css/envelope-viewer.css")" rel="stylesheet" /> <link href="@AppVersion.GetVersionedUrl("css/envelope-viewer.css")" rel="stylesheet" />
@@ -161,7 +168,7 @@
@{ @{
var envelope = cellContext.DataItem as EnvelopeDto; var envelope = cellContext.DataItem as EnvelopeDto;
if (envelope != null) { if (envelope != null) {
var receivers = envelope.EnvelopeReceivers ?? new List<EnvelopeReceiverSimpleDto>(); var receivers = envelope.EnvelopeReceivers?.ToList() ?? [];
var signed = receivers.Count(r => r.Signed); var signed = receivers.Count(r => r.Signed);
var total = receivers.Count; var total = receivers.Count;
<div style="display: flex; align-items: center; gap: 0.5rem;"> <div style="display: flex; align-items: center; gap: 0.5rem;">
@@ -204,7 +211,7 @@
</span> </span>
<div style="flex: 1; font-size: 0.875rem;"> <div style="flex: 1; font-size: 0.875rem;">
<strong style="color: #1f2937;">@receiver.Name</strong> <strong style="color: #1f2937;">@receiver.Name</strong>
<span style="color: #6b7280; margin-left: 0.5rem;">@receiver.Email</span> <span style="color: #6b7280; margin-left: 0.5rem;">@receiver.Receiver?.EmailAddress</span>
</div> </div>
</div> </div>
} }
@@ -257,7 +264,7 @@
@{ @{
var envelope = cellContext.DataItem as EnvelopeDto; var envelope = cellContext.DataItem as EnvelopeDto;
if (envelope != null) { if (envelope != null) {
var receivers = envelope.EnvelopeReceivers ?? new List<EnvelopeReceiverSimpleDto>(); var receivers = envelope.EnvelopeReceivers?.ToList() ?? [];
var signed = receivers.Count(r => r.Signed); var signed = receivers.Count(r => r.Signed);
var total = receivers.Count; var total = receivers.Count;
<div style="display: flex; align-items: center; gap: 0.5rem;"> <div style="display: flex; align-items: center; gap: 0.5rem;">
@@ -300,7 +307,7 @@
</span> </span>
<div style="flex: 1; font-size: 0.875rem;"> <div style="flex: 1; font-size: 0.875rem;">
<strong style="color: #1f2937;">@receiver.Name</strong> <strong style="color: #1f2937;">@receiver.Name</strong>
<span style="color: #6b7280; margin-left: 0.5rem;">@receiver.Email</span> <span style="color: #6b7280; margin-left: 0.5rem;">@receiver.Receiver?.EmailAddress</span>
</div> </div>
</div> </div>
} }
@@ -333,7 +340,7 @@
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
var hasAccess = await AuthService.CheckSenderAsync(); var hasAccess = await AuthService.CheckSenderAccessAsync();
if (!hasAccess) if (!hasAccess)
{ {
Navigation.NavigateTo($"/sender/login"); Navigation.NavigateTo($"/sender/login");
@@ -411,9 +418,8 @@
return status >= EnvelopeStatus.EnvelopeQueued; return status >= EnvelopeStatus.EnvelopeQueued;
} }
(string Label, string CssClass, string DotColor) GetStatusInfo(int statusCode) (string Label, string CssClass, string DotColor) GetStatusInfo(EnvelopeStatus status)
{ {
var status = (EnvelopeStatus)statusCode;
return status switch return status switch
{ {
EnvelopeStatus.EnvelopePartlySigned => ("Teilweise unterschrieben", "partly-signed", "green"), EnvelopeStatus.EnvelopePartlySigned => ("Teilweise unterschrieben", "partly-signed", "green"),

View File

@@ -22,6 +22,17 @@ public class AuthService(IHttpClientFactory httpClientFactory)
return response.StatusCode == HttpStatusCode.OK; return response.StatusCode == HttpStatusCode.OK;
} }
/// <summary>
/// Checks whether the current user holds a valid receiver token for the given envelope key.
/// Calls GET /api/auth/check/envelope/{envelopeKey}.
/// </summary>
public async Task<bool> CheckSenderAccessAsync(CancellationToken cancel = default)
{
using var http = CreateDefaultClient();
var response = await http.GetAsync($"/api/auth/check", cancel);
return response.StatusCode == HttpStatusCode.OK;
}
/// <summary> /// <summary>
/// Submits the access code for the given envelope key. /// Submits the access code for the given envelope key.
/// Calls POST /api/Auth/envelope-receiver/{key} with multipart/form-data. /// Calls POST /api/Auth/envelope-receiver/{key} with multipart/form-data.
@@ -61,6 +72,19 @@ public class AuthService(IHttpClientFactory httpClientFactory)
return response.IsSuccessStatusCode; return response.IsSuccessStatusCode;
} }
/// <summary>
/// Removes the per-envelope receiver cookie for the given envelope key.
/// Calls POST /api/auth/logout/envelope/{envelopeKey}.
/// </summary>
public async Task<bool> LogoutSenderAsync(CancellationToken cancel = default)
{
using var http = CreateDefaultClient();
var response = await http.PostAsync(
$"/api/auth/logout",
null, cancel);
return response.IsSuccessStatusCode;
}
/// <summary> /// <summary>
/// Authenticates a sender user with username and password. /// Authenticates a sender user with username and password.
/// Calls POST /api/auth?cookie=true with JSON body. /// Calls POST /api/auth?cookie=true with JSON body.

View File

@@ -40,17 +40,11 @@ public partial class AuthController(IOptions<AuthTokenKeys> authTokenKeyOptions,
/// <response code="401">Wenn es kein zugelassenes Cookie gibt, wird „nicht zugelassen“ zurückgegeben.</response> /// <response code="401">Wenn es kein zugelassenes Cookie gibt, wird „nicht zugelassen“ zurückgegeben.</response>
[ProducesResponseType(typeof(void), StatusCodes.Status200OK)] [ProducesResponseType(typeof(void), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)] [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
[Authorize(Policy = AuthPolicy.SenderOrReceiver)] [Authorize(Policy = AuthPolicy.Sender)]
[HttpPost("logout")] [HttpPost("logout")]
public async Task<IActionResult> Logout() public IActionResult Logout()
{ {
if (await this.IsUserInPolicyAsync(AuthPolicy.Sender)) Response.Cookies.Delete(authTokenKeys.Cookie);
Response.Cookies.Delete(authTokenKeys.Cookie);
else if (await this.IsUserInPolicyAsync(AuthPolicy.ReceiverOrReceiverTFA))
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
else
return Unauthorized();
return Ok(); return Ok();
} }