forked from gongxuegit/tiku-backend.net
feat: harden SaaS authentication and authorization
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
using System.Text.Json;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Authorization.Policy;
|
||||
using Tiku.Application.Security;
|
||||
using Tiku.Domain.Operations;
|
||||
using Tiku.Infrastructure.Persistence;
|
||||
|
||||
namespace Tiku.Api.Security;
|
||||
|
||||
internal sealed class AuditingAuthorizationMiddlewareResultHandler(
|
||||
IServiceScopeFactory scopeFactory,
|
||||
ILogger<AuditingAuthorizationMiddlewareResultHandler> logger) : IAuthorizationMiddlewareResultHandler
|
||||
{
|
||||
private readonly AuthorizationMiddlewareResultHandler fallback = new();
|
||||
|
||||
public async Task HandleAsync(
|
||||
RequestDelegate next,
|
||||
HttpContext context,
|
||||
AuthorizationPolicy policy,
|
||||
PolicyAuthorizationResult authorizeResult)
|
||||
{
|
||||
if (authorizeResult.Forbidden && context.User.Identity?.IsAuthenticated == true)
|
||||
{
|
||||
try
|
||||
{
|
||||
await using var scope = scopeFactory.CreateAsyncScope();
|
||||
var dbContext = scope.ServiceProvider.GetRequiredService<TikuDbContext>();
|
||||
dbContext.AuditLogs.Add(new AuditLog
|
||||
{
|
||||
TenantId = Guid.TryParse(context.User.FindFirst(TikuClaimTypes.TenantId)?.Value, out var tenantId)
|
||||
? tenantId
|
||||
: null,
|
||||
ActorUserId = Guid.TryParse(context.User.FindFirst(TikuClaimTypes.UserId)?.Value, out var userId)
|
||||
? userId
|
||||
: null,
|
||||
Action = "authorization.access_denied",
|
||||
TargetType = "http_endpoint",
|
||||
TargetId = context.Request.Path,
|
||||
IpAddress = context.Connection.RemoteIpAddress?.ToString(),
|
||||
UserAgent = context.Request.Headers.UserAgent.ToString(),
|
||||
Details = JsonSerializer.SerializeToElement(new
|
||||
{
|
||||
Method = context.Request.Method,
|
||||
Path = context.Request.Path.Value,
|
||||
Realm = context.User.FindFirst(TikuClaimTypes.Realm)?.Value,
|
||||
Failure = authorizeResult.AuthorizationFailure?.FailureReasons.Select(reason => reason.Message).ToArray()
|
||||
})
|
||||
});
|
||||
await dbContext.SaveChangesAsync(context.RequestAborted);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
logger.LogWarning(exception, "Failed to persist authorization denial audit event.");
|
||||
}
|
||||
}
|
||||
|
||||
await fallback.HandleAsync(next, context, policy, authorizeResult);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user