mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-07-16 17:47:22 +00:00
Format ./web/backend/API/API.Core
This commit is contained in:
@@ -8,15 +8,9 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.11" />
|
||||||
Include="Microsoft.AspNetCore.OpenApi"
|
|
||||||
Version="9.0.11"
|
|
||||||
/>
|
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
|
||||||
<PackageReference
|
<PackageReference Include="FluentValidation.AspNetCore" Version="11.3.0" />
|
||||||
Include="FluentValidation.AspNetCore"
|
|
||||||
Version="11.3.0"
|
|
||||||
/>
|
|
||||||
<PackageReference Include="MediatR" Version="12.4.1" />
|
<PackageReference Include="MediatR" Version="12.4.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -44,29 +44,19 @@ public class JwtAuthenticationHandler(
|
|||||||
{
|
{
|
||||||
// Use the same access-token secret source as TokenService to avoid mismatched validation.
|
// Use the same access-token secret source as TokenService to avoid mismatched validation.
|
||||||
string? secret = Environment.GetEnvironmentVariable("ACCESS_TOKEN_SECRET");
|
string? secret = Environment.GetEnvironmentVariable("ACCESS_TOKEN_SECRET");
|
||||||
if (string.IsNullOrWhiteSpace(secret)) secret = configuration["Jwt:SecretKey"];
|
if (string.IsNullOrWhiteSpace(secret))
|
||||||
|
secret = configuration["Jwt:SecretKey"];
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(secret)) return AuthenticateResult.Fail("JWT secret is not configured");
|
if (string.IsNullOrWhiteSpace(secret))
|
||||||
|
return AuthenticateResult.Fail("JWT secret is not configured");
|
||||||
|
|
||||||
// Check if Authorization header exists
|
// Check if Authorization header exists
|
||||||
if (
|
if (!Request.Headers.TryGetValue("Authorization", out StringValues authHeaderValue))
|
||||||
!Request.Headers.TryGetValue(
|
|
||||||
"Authorization",
|
|
||||||
out StringValues authHeaderValue
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return AuthenticateResult.Fail("Authorization header is missing");
|
return AuthenticateResult.Fail("Authorization header is missing");
|
||||||
|
|
||||||
string authHeader = authHeaderValue.ToString();
|
string authHeader = authHeaderValue.ToString();
|
||||||
if (
|
if (!authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
|
||||||
!authHeader.StartsWith(
|
return AuthenticateResult.Fail("Invalid authorization header format");
|
||||||
"Bearer ",
|
|
||||||
StringComparison.OrdinalIgnoreCase
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return AuthenticateResult.Fail(
|
|
||||||
"Invalid authorization header format"
|
|
||||||
);
|
|
||||||
|
|
||||||
string token = authHeader.Substring("Bearer ".Length).Trim();
|
string token = authHeader.Substring("Bearer ".Length).Trim();
|
||||||
|
|
||||||
@@ -81,9 +71,7 @@ public class JwtAuthenticationHandler(
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
return AuthenticateResult.Fail(
|
return AuthenticateResult.Fail($"Token validation failed: {ex.Message}");
|
||||||
$"Token validation failed: {ex.Message}"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +85,10 @@ public class JwtAuthenticationHandler(
|
|||||||
Response.ContentType = "application/json";
|
Response.ContentType = "application/json";
|
||||||
Response.StatusCode = 401;
|
Response.StatusCode = 401;
|
||||||
|
|
||||||
ResponseBody response = new() { Message = "Unauthorized: Invalid or missing authentication token" };
|
ResponseBody response = new()
|
||||||
|
{
|
||||||
|
Message = "Unauthorized: Invalid or missing authentication token",
|
||||||
|
};
|
||||||
await Response.WriteAsJsonAsync(response);
|
await Response.WriteAsJsonAsync(response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -106,6 +97,4 @@ public class JwtAuthenticationHandler(
|
|||||||
/// Options for the <c>JWT</c> authentication scheme handled by <see cref="JwtAuthenticationHandler" />.
|
/// Options for the <c>JWT</c> authentication scheme handled by <see cref="JwtAuthenticationHandler" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>No additional options are defined beyond those provided by <see cref="AuthenticationSchemeOptions" />.</remarks>
|
/// <remarks>No additional options are defined beyond those provided by <see cref="AuthenticationSchemeOptions" />.</remarks>
|
||||||
public class JwtAuthenticationOptions : AuthenticationSchemeOptions
|
public class JwtAuthenticationOptions : AuthenticationSchemeOptions { }
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public class ProtectedController : ControllerBase
|
|||||||
new ResponseBody<object>
|
new ResponseBody<object>
|
||||||
{
|
{
|
||||||
Message = "Protected endpoint accessed successfully",
|
Message = "Protected endpoint accessed successfully",
|
||||||
Payload = new { userId, username }
|
Payload = new { userId, username },
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,7 @@ namespace API.Core;
|
|||||||
/// consistent JSON error responses with appropriate HTTP status codes.
|
/// consistent JSON error responses with appropriate HTTP status codes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="logger">Logger used to record unhandled exceptions before they are translated into a response.</param>
|
/// <param name="logger">Logger used to record unhandled exceptions before they are translated into a response.</param>
|
||||||
public class GlobalExceptionFilter(ILogger<GlobalExceptionFilter> logger)
|
public class GlobalExceptionFilter(ILogger<GlobalExceptionFilter> logger) : IExceptionFilter
|
||||||
: IExceptionFilter
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Logs the exception and sets <see cref="ExceptionContext.Result" /> to an appropriate error response,
|
/// Logs the exception and sets <see cref="ExceptionContext.Result" /> to an appropriate error response,
|
||||||
@@ -84,10 +83,7 @@ public class GlobalExceptionFilter(ILogger<GlobalExceptionFilter> logger)
|
|||||||
case ValidationException fluentValidationException:
|
case ValidationException fluentValidationException:
|
||||||
Dictionary<string, string[]> errors = fluentValidationException
|
Dictionary<string, string[]> errors = fluentValidationException
|
||||||
.Errors.GroupBy(e => e.PropertyName)
|
.Errors.GroupBy(e => e.PropertyName)
|
||||||
.ToDictionary(
|
.ToDictionary(g => g.Key, g => g.Select(e => e.ErrorMessage).ToArray());
|
||||||
g => g.Key,
|
|
||||||
g => g.Select(e => e.ErrorMessage).ToArray()
|
|
||||||
);
|
|
||||||
|
|
||||||
context.Result = new BadRequestObjectResult(
|
context.Result = new BadRequestObjectResult(
|
||||||
new { message = "Validation failed", errors }
|
new { message = "Validation failed", errors }
|
||||||
@@ -96,41 +92,33 @@ public class GlobalExceptionFilter(ILogger<GlobalExceptionFilter> logger)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ConflictException ex:
|
case ConflictException ex:
|
||||||
context.Result = new ObjectResult(
|
context.Result = new ObjectResult(new ResponseBody { Message = ex.Message })
|
||||||
new ResponseBody { Message = ex.Message }
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
StatusCode = 409
|
StatusCode = 409,
|
||||||
};
|
};
|
||||||
context.ExceptionHandled = true;
|
context.ExceptionHandled = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NotFoundException ex:
|
case NotFoundException ex:
|
||||||
context.Result = new ObjectResult(
|
context.Result = new ObjectResult(new ResponseBody { Message = ex.Message })
|
||||||
new ResponseBody { Message = ex.Message }
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
StatusCode = 404
|
StatusCode = 404,
|
||||||
};
|
};
|
||||||
context.ExceptionHandled = true;
|
context.ExceptionHandled = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UnauthorizedException ex:
|
case UnauthorizedException ex:
|
||||||
context.Result = new ObjectResult(
|
context.Result = new ObjectResult(new ResponseBody { Message = ex.Message })
|
||||||
new ResponseBody { Message = ex.Message }
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
StatusCode = 401
|
StatusCode = 401,
|
||||||
};
|
};
|
||||||
context.ExceptionHandled = true;
|
context.ExceptionHandled = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ForbiddenException ex:
|
case ForbiddenException ex:
|
||||||
context.Result = new ObjectResult(
|
context.Result = new ObjectResult(new ResponseBody { Message = ex.Message })
|
||||||
new ResponseBody { Message = ex.Message }
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
StatusCode = 403
|
StatusCode = 403,
|
||||||
};
|
};
|
||||||
context.ExceptionHandled = true;
|
context.ExceptionHandled = true;
|
||||||
break;
|
break;
|
||||||
@@ -140,30 +128,25 @@ public class GlobalExceptionFilter(ILogger<GlobalExceptionFilter> logger)
|
|||||||
new ResponseBody { Message = "A database error occurred." }
|
new ResponseBody { Message = "A database error occurred." }
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
StatusCode = 503
|
StatusCode = 503,
|
||||||
};
|
};
|
||||||
context.ExceptionHandled = true;
|
context.ExceptionHandled = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Domain.Exceptions.ValidationException ex:
|
case Domain.Exceptions.ValidationException ex:
|
||||||
context.Result = new ObjectResult(
|
context.Result = new ObjectResult(new ResponseBody { Message = ex.Message })
|
||||||
new ResponseBody { Message = ex.Message }
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
StatusCode = 400
|
StatusCode = 400,
|
||||||
};
|
};
|
||||||
context.ExceptionHandled = true;
|
context.ExceptionHandled = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
context.Result = new ObjectResult(
|
context.Result = new ObjectResult(
|
||||||
new ResponseBody
|
new ResponseBody { Message = "An unexpected error occurred" }
|
||||||
{
|
|
||||||
Message = "An unexpected error occurred"
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
StatusCode = 500
|
StatusCode = 500,
|
||||||
};
|
};
|
||||||
context.ExceptionHandled = true;
|
context.ExceptionHandled = true;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -17,7 +17,11 @@ using Shared.Application.Behaviors;
|
|||||||
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
|
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
// Global Exception Filter
|
// Global Exception Filter
|
||||||
builder.Services.AddControllers(options => { options.Filters.Add<GlobalExceptionFilter>(); })
|
builder
|
||||||
|
.Services.AddControllers(options =>
|
||||||
|
{
|
||||||
|
options.Filters.Add<GlobalExceptionFilter>();
|
||||||
|
})
|
||||||
.AddApplicationPart(typeof(BreweryController).Assembly)
|
.AddApplicationPart(typeof(BreweryController).Assembly)
|
||||||
.AddApplicationPart(typeof(UserController).Assembly)
|
.AddApplicationPart(typeof(UserController).Assembly)
|
||||||
.AddApplicationPart(typeof(AuthController).Assembly);
|
.AddApplicationPart(typeof(AuthController).Assembly);
|
||||||
@@ -51,14 +55,12 @@ builder.Services.AddHealthChecks();
|
|||||||
// Configure logging for container output
|
// Configure logging for container output
|
||||||
builder.Logging.ClearProviders();
|
builder.Logging.ClearProviders();
|
||||||
builder.Logging.AddConsole();
|
builder.Logging.AddConsole();
|
||||||
if (!builder.Environment.IsProduction()) builder.Logging.AddDebug();
|
if (!builder.Environment.IsProduction())
|
||||||
|
builder.Logging.AddDebug();
|
||||||
|
|
||||||
// Configure Dependency Injection -------------------------------------------------------------------------------------
|
// Configure Dependency Injection -------------------------------------------------------------------------------------
|
||||||
|
|
||||||
builder.Services.AddSingleton<
|
builder.Services.AddSingleton<ISqlConnectionFactory, DefaultSqlConnectionFactory>();
|
||||||
ISqlConnectionFactory,
|
|
||||||
DefaultSqlConnectionFactory
|
|
||||||
>();
|
|
||||||
|
|
||||||
builder.Services.AddFeaturesBreweries();
|
builder.Services.AddFeaturesBreweries();
|
||||||
builder.Services.AddFeaturesUserManagement();
|
builder.Services.AddFeaturesUserManagement();
|
||||||
@@ -75,10 +77,7 @@ builder.Services.AddScoped<GlobalExceptionFilter>();
|
|||||||
// Configure JWT Authentication
|
// Configure JWT Authentication
|
||||||
builder
|
builder
|
||||||
.Services.AddAuthentication("JWT")
|
.Services.AddAuthentication("JWT")
|
||||||
.AddScheme<JwtAuthenticationOptions, JwtAuthenticationHandler>(
|
.AddScheme<JwtAuthenticationOptions, JwtAuthenticationHandler>("JWT", options => { });
|
||||||
"JWT",
|
|
||||||
options => { }
|
|
||||||
);
|
|
||||||
|
|
||||||
builder.Services.AddAuthorization();
|
builder.Services.AddAuthorization();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user