Refactor JWT token generation and update password handling logic; add exception handling behavior
This commit is contained in:
@@ -15,16 +15,16 @@
|
||||
|
||||
<PackageReference Include="Mapster.DependencyInjection" Version="1.0.0" />
|
||||
<PackageReference Include="MediatR" Version="11.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.0">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.11">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="9.0.11" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.18.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Grpc.Swagger" Version="0.3.8" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="7.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.MSSqlServer" Version="6.3.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Seq" Version="5.2.2" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.MSSqlServer" Version="9.0.2" />
|
||||
<PackageReference Include="Serilog.Sinks.Seq" Version="9.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
// filepath: /media/masoud/Project/FourSat/CMS/src/CMSMicroservice.WebApi/Common/Behaviours/ExceptionHandlingBehaviour.cs
|
||||
using System.Text.Json;
|
||||
using System.Collections.Generic;
|
||||
using CMSMicroservice.Application.Common.Exceptions;
|
||||
using Grpc.Core;
|
||||
using Grpc.Core.Interceptors;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CMSMicroservice.WebApi.Common.Behaviours;
|
||||
|
||||
public class ExceptionHandlingBehaviour : Interceptor
|
||||
{
|
||||
private readonly ILogger<ExceptionHandlingBehaviour> _logger;
|
||||
|
||||
public ExceptionHandlingBehaviour(ILogger<ExceptionHandlingBehaviour> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
|
||||
TRequest request,
|
||||
ServerCallContext context,
|
||||
UnaryServerMethod<TRequest, TResponse> continuation)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await continuation(request, context);
|
||||
}
|
||||
catch (ValidationException vex)
|
||||
{
|
||||
// Flatten validation errors into a trailer so clients can display them
|
||||
var metadata = new Metadata();
|
||||
string description = vex.Message;
|
||||
try
|
||||
{
|
||||
if (vex.Errors is { Count: > 0 })
|
||||
{
|
||||
var payload = JsonSerializer.Serialize(vex.Errors);
|
||||
metadata.Add("validation-errors-text", payload);
|
||||
|
||||
// Build a human-friendly description out of individual messages
|
||||
var parts = new List<string>();
|
||||
foreach (var kv in vex.Errors)
|
||||
{
|
||||
foreach (var msg in kv.Value)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(kv.Key))
|
||||
parts.Add($"{kv.Key}: {msg}");
|
||||
else
|
||||
parts.Add(msg);
|
||||
}
|
||||
}
|
||||
if (parts.Count > 0)
|
||||
{
|
||||
description = string.Join(" | ", parts);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore serialization issues, still return InvalidArgument
|
||||
}
|
||||
|
||||
_logger.LogWarning(vex, "Validation failed for request {Method}", context.Method);
|
||||
throw new RpcException(new Status(StatusCode.InvalidArgument, description), metadata);
|
||||
}
|
||||
catch (NotFoundException nfex)
|
||||
{
|
||||
_logger.LogInformation(nfex, "Entity not found for request {Method}", context.Method);
|
||||
throw new RpcException(new Status(StatusCode.NotFound, nfex.Message));
|
||||
}
|
||||
catch (UnauthorizedAccessException uaex)
|
||||
{
|
||||
_logger.LogInformation(uaex, "Unauthorized access for request {Method}", context.Method);
|
||||
throw new RpcException(new Status(StatusCode.Unauthenticated, uaex.Message));
|
||||
}
|
||||
catch (ForbiddenAccessException fax)
|
||||
{
|
||||
_logger.LogInformation(fax, "Forbidden access for request {Method}", context.Method);
|
||||
throw new RpcException(new Status(StatusCode.PermissionDenied, fax.Message));
|
||||
}
|
||||
catch (DuplicateException dex)
|
||||
{
|
||||
_logger.LogInformation(dex, "Duplicate resource for request {Method}", context.Method);
|
||||
throw new RpcException(new Status(StatusCode.AlreadyExists, dex.Message));
|
||||
}
|
||||
catch (ArgumentException aex)
|
||||
{
|
||||
_logger.LogInformation(aex, "Invalid argument for request {Method}", context.Method);
|
||||
throw new RpcException(new Status(StatusCode.InvalidArgument, aex.Message));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Unhandled exception for request {Method}", context.Method);
|
||||
// Hide internal details from clients
|
||||
throw new RpcException(new Status(StatusCode.Internal, "Internal server error"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ builder.Services.AddGrpc(options =>
|
||||
{
|
||||
options.Interceptors.Add<LoggingBehaviour>();
|
||||
options.Interceptors.Add<PerformanceBehaviour>();
|
||||
//options.Interceptors.Add<ExceptionHandlingBehaviour>();
|
||||
options.EnableDetailedErrors = true;
|
||||
options.MaxReceiveMessageSize = 1000 * 1024 * 1024; // 1 GB
|
||||
options.MaxSendMessageSize = 1000 * 1024 * 1024; // 1 GB
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"JwtSecurityKey": "TvlZVx5TJaHs8e9HgUdGzhGP2CIidoI444nAj+8+g7c=",
|
||||
"JwtIssuer": "https://localhost",
|
||||
"JwtAudience": "https://localhost",
|
||||
"JwtExpiryInDays": 365,
|
||||
"JwtExpiryInDays": 5,
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection": "Data Source=185.252.31.42,2019; Initial Catalog=Foursat;User ID=afrino;Password=87zH26nbqT%;Connection Timeout=300000;MultipleActiveResultSets=True;Encrypt=False",
|
||||
"providerName": "System.Data.SqlClient"
|
||||
|
||||
Reference in New Issue
Block a user