Add recent auth log attempts to user details page (#948)

This commit is contained in:
Leendert de Borst
2025-06-20 19:26:21 +02:00
committed by Leendert de Borst
parent 516dd524df
commit 15bb7f6593
4 changed files with 115 additions and 2 deletions

View File

@@ -0,0 +1,84 @@
@using AliasVault.RazorComponents.Tables
@using AliasVault.Shared.Models.Enums
<div class="mb-4 mt-3">
<LinkButton Color="primary" Href="@($"logging/auth?search={Uri.EscapeDataString(Username)}")" Text="View all auth logs for this user" />
</div>
@if (AuthLogList.Any())
{
<SortableTable Columns="@_authLogTableColumns" SortColumn="@SortColumn" SortDirection="@SortDirection" OnSortChanged="HandleSortChanged">
@foreach (var log in SortedAuthLogList)
{
<SortableTableRow>
<SortableTableColumn IsPrimary="true">@log.Id</SortableTableColumn>
<SortableTableColumn>@log.Timestamp.ToString("yyyy-MM-dd HH:mm")</SortableTableColumn>
<SortableTableColumn>@log.EventType</SortableTableColumn>
<SortableTableColumn><StatusPill Enabled="log.IsSuccess" TextTrue="Success" TextFalse="@log.FailureReason.ToString()" /></SortableTableColumn>
<SortableTableColumn>@log.IpAddress</SortableTableColumn>
<SortableTableColumn>@log.Client</SortableTableColumn>
</SortableTableRow>
}
</SortableTable>
}
else
{
<div class="flex items-center justify-center py-8">
<div class="text-center">
<div class="text-gray-500 dark:text-gray-400">
<i class="fas fa-history text-4xl mb-4"></i>
</div>
<h3 class="text-lg font-medium text-gray-900 dark:text-white">No authentication logs</h3>
<p class="text-sm text-gray-500 dark:text-gray-400">This user has no recent authentication attempts.</p>
</div>
</div>
}
@code {
/// <summary>
/// Gets or sets the username for linking to full auth logs.
/// </summary>
[Parameter]
public string Username { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the list of auth logs to display (should be limited to recent logs).
/// </summary>
[Parameter]
public List<AuthLog> AuthLogList { get; set; } = [];
private string SortColumn { get; set; } = "Timestamp";
private SortDirection SortDirection { get; set; } = SortDirection.Descending;
private readonly List<TableColumn> _authLogTableColumns = [
new TableColumn { Title = "ID", PropertyName = "Id" },
new TableColumn { Title = "Time", PropertyName = "Timestamp" },
new TableColumn { Title = "Event", PropertyName = "EventType" },
new TableColumn { Title = "Success", PropertyName = "IsSuccess" },
new TableColumn { Title = "IP", PropertyName = "IpAddress" },
new TableColumn { Title = "Client", PropertyName = "Client" },
];
private IEnumerable<AuthLog> SortedAuthLogList => SortList(AuthLogList, SortColumn, SortDirection);
private void HandleSortChanged((string column, SortDirection direction) sort)
{
SortColumn = sort.column;
SortDirection = sort.direction;
StateHasChanged();
}
private static IEnumerable<AuthLog> SortList(List<AuthLog> authLogs, string sortColumn, SortDirection sortDirection)
{
return sortColumn switch
{
"Id" => SortableTable.SortListByProperty(authLogs, a => a.Id, sortDirection),
"Timestamp" => SortableTable.SortListByProperty(authLogs, a => a.Timestamp, sortDirection),
"EventType" => SortableTable.SortListByProperty(authLogs, a => a.EventType, sortDirection),
"IsSuccess" => SortableTable.SortListByProperty(authLogs, a => a.IsSuccess, sortDirection),
"IpAddress" => SortableTable.SortListByProperty(authLogs, a => a.IpAddress, sortDirection),
"Client" => SortableTable.SortListByProperty(authLogs, a => a.Client, sortDirection),
_ => authLogs
};
}
}

View File

@@ -1,7 +1,7 @@
@using AliasVault.RazorComponents.Tables
<div class="d-flex justify-content-between mb-3">
<div class="flex items-center space-x-2">
<div class="flex items-center space-x-2 mt-2">
<Button Color="secondary" OnClick="ToggleShowDisabled">
@(ShowDisabled ? "Hide Disabled Claims" : "Show Disabled Claims")
</Button>
@@ -134,7 +134,7 @@ else
StateHasChanged();
}
/// <summary>
/// <summary>
/// This method will toggle the disabled status of an email claim.
/// </summary>
private async Task ToggleEmailClaimStatus(UserEmailClaimWithCount entry)

View File

@@ -101,6 +101,18 @@ else
</div>
</div>
<div class="p-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm dark:border-gray-700 sm:p-6 dark:bg-gray-800">
<div class="items-center">
<div>
<h3 class="mb-1 text-xl font-bold text-gray-900 dark:text-white">Recent authentication logs</h3>
<p class="text-sm text-gray-500 dark:text-gray-400">
Shows the last 5 authentication attempts for this user. Click "View all auth logs" to see complete history.
</p>
<AuthLogTable Username="@(User?.UserName ?? string.Empty)" AuthLogList="@AuthLogList" />
</div>
</div>
</div>
<div class="p-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm dark:border-gray-700 sm:p-6 dark:bg-gray-800">
<div class="items-center">
<div>
@@ -130,6 +142,7 @@ else
private int TwoFactorKeysCount { get; set; }
private List<AliasVaultUserRefreshToken> RefreshTokenList { get; set; } = [];
private List<Vault> VaultList { get; set; } = [];
private List<AuthLog> AuthLogList { get; set; } = [];
/// <inheritdoc />
protected override async Task OnInitializedAsync()
@@ -204,6 +217,13 @@ else
.OrderBy(x => x.UpdatedAt)
.ToListAsync();
// Load recent auth logs for this user (last 3 records).
AuthLogList = await dbContext.AuthLogs
.Where(x => x.Username == User.UserName)
.OrderByDescending(x => x.Timestamp)
.Take(5)
.ToListAsync();
IsLoading = false;
StateHasChanged();
}

View File

@@ -1541,6 +1541,11 @@ video {
line-height: 1rem;
}
.text-4xl {
font-size: 2.25rem;
line-height: 2.5rem;
}
.font-bold {
font-weight: 700;
}
@@ -1561,6 +1566,10 @@ video {
font-weight: 600;
}
.italic {
font-style: italic;
}
.leading-6 {
line-height: 1.5rem;
}