Refactor JWT token generation and update password handling logic; add exception handling behavior
This commit is contained in:
@@ -7,11 +7,11 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.2.2" />
|
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.2.2" />
|
||||||
<PackageReference Include="Mapster" Version="7.3.0" />
|
<PackageReference Include="Mapster" Version="7.4.0" />
|
||||||
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="11.0.0" />
|
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="11.0.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.11" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="7.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.11" />
|
||||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.3.2" />
|
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.6.10" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\CMSMicroservice.Domain\CMSMicroservice.Domain.csproj" />
|
<ProjectReference Include="..\CMSMicroservice.Domain\CMSMicroservice.Domain.csproj" />
|
||||||
|
|||||||
@@ -11,12 +11,30 @@ public class ValidationException : Exception
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ValidationException(IEnumerable<ValidationFailure> failures)
|
public ValidationException(IEnumerable<ValidationFailure> failures)
|
||||||
: this()
|
: base(BuildMessage(failures, out var errors))
|
||||||
{
|
{
|
||||||
Errors = failures
|
Errors = errors;
|
||||||
.GroupBy(e => e.PropertyName, e => e.ErrorMessage)
|
|
||||||
.ToDictionary(failureGroup => failureGroup.Key, failureGroup => failureGroup.ToArray());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDictionary<string, string[]> Errors { get; }
|
public IDictionary<string, string[]> Errors { get; }
|
||||||
|
|
||||||
|
private static string BuildMessage(IEnumerable<ValidationFailure> failures, out IDictionary<string, string[]> errors)
|
||||||
|
{
|
||||||
|
var list = failures?.Where(f => !string.IsNullOrWhiteSpace(f.ErrorMessage)).ToList() ?? new List<ValidationFailure>();
|
||||||
|
|
||||||
|
errors = list
|
||||||
|
.GroupBy(e => e.PropertyName, e => e.ErrorMessage)
|
||||||
|
.ToDictionary(failureGroup => failureGroup.Key, failureGroup => failureGroup.ToArray());
|
||||||
|
|
||||||
|
var items = list
|
||||||
|
.Select(f => string.IsNullOrWhiteSpace(f.PropertyName)
|
||||||
|
? f.ErrorMessage
|
||||||
|
: $"{f.PropertyName}: {f.ErrorMessage}")
|
||||||
|
.Where(s => !string.IsNullOrWhiteSpace(s))
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
return items.Length > 0
|
||||||
|
? string.Join(" | ", items)
|
||||||
|
: "One or more validation failures have occurred.";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
namespace CMSMicroservice.Application.Common.Interfaces;
|
namespace CMSMicroservice.Application.Common.Interfaces;
|
||||||
public interface IGenerateJwtToken
|
public interface IGenerateJwtToken
|
||||||
{
|
{
|
||||||
Task<string> GenerateJwtToken(User user);
|
Task<string> GenerateJwtToken(User user,int? expiryDays=null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,15 +3,50 @@ namespace CMSMicroservice.Application.UserCQ.Commands.SetPasswordForUser;
|
|||||||
public class SetPasswordForUserCommandHandler : IRequestHandler<SetPasswordForUserCommand, Unit>
|
public class SetPasswordForUserCommandHandler : IRequestHandler<SetPasswordForUserCommand, Unit>
|
||||||
{
|
{
|
||||||
private readonly IApplicationDbContext _context;
|
private readonly IApplicationDbContext _context;
|
||||||
|
private readonly IHashService _hashService;
|
||||||
|
|
||||||
public SetPasswordForUserCommandHandler(IApplicationDbContext context)
|
public SetPasswordForUserCommandHandler(IApplicationDbContext context, IHashService hashService)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
|
_hashService = hashService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Unit> Handle(SetPasswordForUserCommand request, CancellationToken cancellationToken)
|
public async Task<Unit> Handle(SetPasswordForUserCommand request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
//TODO: Implement your business logic
|
// basic validations
|
||||||
return new Unit();
|
if (!string.Equals(request.NewPassword, request.ConfirmPassword, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
throw new CMSMicroservice.Application.Common.Exceptions.ValidationException(new[]
|
||||||
|
{
|
||||||
|
new FluentValidation.Results.ValidationFailure(nameof(request.ConfirmPassword), "کلمه عبور و تایید آن یکسان نیستند.")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var user = await _context.Users.FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken)
|
||||||
|
?? throw new NotFoundException(nameof(User), request.UserId);
|
||||||
|
|
||||||
|
var hasExistingPassword = !string.IsNullOrWhiteSpace(user.HashPassword);
|
||||||
|
if (hasExistingPassword)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(request.CurrentPassword))
|
||||||
|
{
|
||||||
|
throw new CMSMicroservice.Application.Common.Exceptions.ValidationException(new[]
|
||||||
|
{
|
||||||
|
new FluentValidation.Results.ValidationFailure(nameof(request.CurrentPassword), "کلمه عبور فعلی الزامی است.")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!_hashService.VerifyPassword(request.CurrentPassword, user.HashPassword))
|
||||||
|
{
|
||||||
|
throw new UnauthorizedAccessException("کلمه عبور فعلی نادرست است.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set new password (PBKDF2)
|
||||||
|
user.HashPassword = _hashService.HashPassword(request.NewPassword);
|
||||||
|
_context.Users.Update(user);
|
||||||
|
user.AddDomainEvent(new CMSMicroservice.Domain.Events.SetPasswordForUserEvent(user));
|
||||||
|
await _context.SaveChangesAsync(cancellationToken);
|
||||||
|
|
||||||
|
return Unit.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using CMSMicroservice.Domain.Events;
|
using CMSMicroservice.Domain.Events;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace CMSMicroservice.Application.UserCQ.EventHandlers;
|
namespace CMSMicroservice.Application.UserCQ.EventHandlers.SetPasswordForUserEventHandlers;
|
||||||
|
|
||||||
public class SetPasswordForUserEventHandler : INotificationHandler<SetPasswordForUserEvent>
|
public class SetPasswordForUserEventHandler : INotificationHandler<SetPasswordForUserEvent>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,18 +1,21 @@
|
|||||||
namespace CMSMicroservice.Application.UserCQ.Queries.AdminGetJwtToken;
|
namespace CMSMicroservice.Application.UserCQ.Queries.AdminGetJwtToken;
|
||||||
|
|
||||||
public class AdminGetJwtTokenQueryHandler : IRequestHandler<AdminGetJwtTokenQuery, AdminGetJwtTokenResponseDto>
|
public class AdminGetJwtTokenQueryHandler : IRequestHandler<AdminGetJwtTokenQuery, AdminGetJwtTokenResponseDto>
|
||||||
{
|
{
|
||||||
private readonly IApplicationDbContext _context;
|
private readonly IApplicationDbContext _context;
|
||||||
private readonly IGenerateJwtToken _generateJwt;
|
private readonly IGenerateJwtToken _generateJwt;
|
||||||
private readonly IHashService _hashService;
|
private readonly IHashService _hashService;
|
||||||
|
|
||||||
public AdminGetJwtTokenQueryHandler(IApplicationDbContext context, IGenerateJwtToken generateJwt, IHashService hashService)
|
public AdminGetJwtTokenQueryHandler(IApplicationDbContext context, IGenerateJwtToken generateJwt,
|
||||||
|
IHashService hashService)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
_generateJwt = generateJwt;
|
_generateJwt = generateJwt;
|
||||||
_hashService = hashService;
|
_hashService = hashService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<AdminGetJwtTokenResponseDto> Handle(AdminGetJwtTokenQuery request, CancellationToken cancellationToken)
|
public async Task<AdminGetJwtTokenResponseDto> Handle(AdminGetJwtTokenQuery request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var user = await _context.Users
|
var user = await _context.Users
|
||||||
.Include(u => u.UserRoles)
|
.Include(u => u.UserRoles)
|
||||||
@@ -21,14 +24,16 @@ public class AdminGetJwtTokenQueryHandler : IRequestHandler<AdminGetJwtTokenQuer
|
|||||||
if (user == null)
|
if (user == null)
|
||||||
throw new Exception("Invalid username or password.");
|
throw new Exception("Invalid username or password.");
|
||||||
|
|
||||||
|
if (user.UserRoles.All(a => a.RoleId != 2))
|
||||||
|
throw new Exception("You do not have permission to do that.");
|
||||||
|
|
||||||
// verify password (supports PBKDF2 or legacy SHA-256)
|
// verify password (supports PBKDF2 or legacy SHA-256)
|
||||||
if (!_hashService.VerifyPassword(request.Password, user.HashPassword))
|
if (!_hashService.VerifyPassword(request.Password, user.HashPassword))
|
||||||
throw new Exception("Invalid username or password.");
|
throw new Exception("Invalid username or password.");
|
||||||
|
|
||||||
return new AdminGetJwtTokenResponseDto()
|
return new AdminGetJwtTokenResponseDto()
|
||||||
{
|
{
|
||||||
Token = await _generateJwt.GenerateJwtToken(user),
|
Token = await _generateJwt.GenerateJwtToken(user,15),
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,7 @@ public class SetPasswordForUserEvent : BaseEvent
|
|||||||
{
|
{
|
||||||
public SetPasswordForUserEvent(User item)
|
public SetPasswordForUserEvent(User item)
|
||||||
{
|
{
|
||||||
|
Item = item;
|
||||||
}
|
}
|
||||||
public User Item { get; }
|
public User Item { get; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,15 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.11" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="7.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="9.0.11" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.11" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.0">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.11">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.0" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="9.0.11" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.11" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ namespace CMSMicroservice.Infrastructure.Persistence.Migrations
|
|||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.HasDefaultSchema("CMS")
|
.HasDefaultSchema("CMS")
|
||||||
.HasAnnotation("ProductVersion", "7.0.0")
|
.HasAnnotation("ProductVersion", "9.0.11")
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||||
|
|
||||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||||
@@ -474,6 +474,9 @@ namespace CMSMicroservice.Infrastructure.Persistence.Migrations
|
|||||||
b.Property<string>("FirstName")
|
b.Property<string>("FirstName")
|
||||||
.HasColumnType("nvarchar(max)");
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("HashPassword")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
b.Property<bool>("IsDeleted")
|
b.Property<bool>("IsDeleted")
|
||||||
.HasColumnType("bit");
|
.HasColumnType("bit");
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public class GenerateJwtTokenService : IGenerateJwtToken
|
|||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> GenerateJwtToken(User user)
|
public async Task<string> GenerateJwtToken(User user,int? expiryDays=null)
|
||||||
{
|
{
|
||||||
var lastModified = user.LastModified ?? user.Created;
|
var lastModified = user.LastModified ?? user.Created;
|
||||||
var claims = new List<Claim>
|
var claims = new List<Claim>
|
||||||
@@ -51,7 +51,10 @@ public class GenerateJwtTokenService : IGenerateJwtToken
|
|||||||
|
|
||||||
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JwtSecurityKey"]));
|
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JwtSecurityKey"]));
|
||||||
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
|
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
|
||||||
var expiry = DateTime.Now.AddDays(Convert.ToInt32(_configuration["JwtExpiryInDays"]));
|
var expiry =expiryDays!=null?
|
||||||
|
DateTime.Now.AddDays(Convert.ToInt32(expiryDays))
|
||||||
|
:
|
||||||
|
DateTime.Now.AddDays(Convert.ToInt32(_configuration["JwtExpiryInDays"]));
|
||||||
|
|
||||||
var token = new JwtSecurityToken(
|
var token = new JwtSecurityToken(
|
||||||
_configuration["JwtIssuer"],
|
_configuration["JwtIssuer"],
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<Version>0.0.117</Version>
|
<Version>0.0.118</Version>
|
||||||
<DebugType>None</DebugType>
|
<DebugType>None</DebugType>
|
||||||
<DebugSymbols>False</DebugSymbols>
|
<DebugSymbols>False</DebugSymbols>
|
||||||
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||||
|
|||||||
@@ -15,16 +15,16 @@
|
|||||||
|
|
||||||
<PackageReference Include="Mapster.DependencyInjection" Version="1.0.0" />
|
<PackageReference Include="Mapster.DependencyInjection" Version="1.0.0" />
|
||||||
<PackageReference Include="MediatR" Version="11.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>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</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.VisualStudio.Azure.Containers.Tools.Targets" Version="1.18.1" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Grpc.Swagger" Version="0.3.8" />
|
<PackageReference Include="Microsoft.AspNetCore.Grpc.Swagger" Version="0.3.8" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="7.0.0" />
|
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.MSSqlServer" Version="6.3.0" />
|
<PackageReference Include="Serilog.Sinks.MSSqlServer" Version="9.0.2" />
|
||||||
<PackageReference Include="Serilog.Sinks.Seq" Version="5.2.2" />
|
<PackageReference Include="Serilog.Sinks.Seq" Version="9.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<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<LoggingBehaviour>();
|
||||||
options.Interceptors.Add<PerformanceBehaviour>();
|
options.Interceptors.Add<PerformanceBehaviour>();
|
||||||
|
//options.Interceptors.Add<ExceptionHandlingBehaviour>();
|
||||||
options.EnableDetailedErrors = true;
|
options.EnableDetailedErrors = true;
|
||||||
options.MaxReceiveMessageSize = 1000 * 1024 * 1024; // 1 GB
|
options.MaxReceiveMessageSize = 1000 * 1024 * 1024; // 1 GB
|
||||||
options.MaxSendMessageSize = 1000 * 1024 * 1024; // 1 GB
|
options.MaxSendMessageSize = 1000 * 1024 * 1024; // 1 GB
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"JwtSecurityKey": "TvlZVx5TJaHs8e9HgUdGzhGP2CIidoI444nAj+8+g7c=",
|
"JwtSecurityKey": "TvlZVx5TJaHs8e9HgUdGzhGP2CIidoI444nAj+8+g7c=",
|
||||||
"JwtIssuer": "https://localhost",
|
"JwtIssuer": "https://localhost",
|
||||||
"JwtAudience": "https://localhost",
|
"JwtAudience": "https://localhost",
|
||||||
"JwtExpiryInDays": 365,
|
"JwtExpiryInDays": 5,
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"DefaultConnection": "Data Source=185.252.31.42,2019; Initial Catalog=Foursat;User ID=afrino;Password=87zH26nbqT%;Connection Timeout=300000;MultipleActiveResultSets=True;Encrypt=False",
|
"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"
|
"providerName": "System.Data.SqlClient"
|
||||||
|
|||||||
Reference in New Issue
Block a user