Add support for cookie-based JWT authentication alongside the existing Authorization header.
This commit is contained in:
parent
2f0d63a90f
commit
eaecace48d
5 changed files with 62 additions and 6 deletions
|
@ -0,0 +1,8 @@
|
|||
using Guestbooky.API.Enums;
|
||||
|
||||
namespace Guestbooky.API.Configurations;
|
||||
|
||||
public class APISettings
|
||||
{
|
||||
public required RunningEnvironment RunningEnvironment { get; set; }
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using Guestbooky.API.DTOs.Auth;
|
||||
using Guestbooky.API.Configurations;
|
||||
using Guestbooky.API.DTOs.Auth;
|
||||
using Guestbooky.Application.UseCases.AuthenticateUser;
|
||||
using Guestbooky.Application.UseCases.RefreshToken;
|
||||
using MediatR;
|
||||
|
@ -12,11 +13,13 @@ public class AuthController : ControllerBase
|
|||
{
|
||||
private readonly IMediator _mediator;
|
||||
private readonly ILogger<AuthController> _logger;
|
||||
private readonly APISettings _apiSettings;
|
||||
|
||||
public AuthController(IMediator mediator, ILogger<AuthController> logger)
|
||||
public AuthController(IMediator mediator, ILogger<AuthController> logger, APISettings apiSettings)
|
||||
{
|
||||
_mediator = mediator;
|
||||
_logger = logger;
|
||||
_apiSettings = apiSettings;
|
||||
}
|
||||
|
||||
[ProducesResponseType(typeof(LoginResponseDto), 200)]
|
||||
|
@ -35,6 +38,7 @@ public class AuthController : ControllerBase
|
|||
if(result.IsAuthenticated)
|
||||
{
|
||||
_logger.LogInformation("Authentication successful. Returning LoginResponse.");
|
||||
SetJwtCookie(result.Token);
|
||||
return Ok(new LoginResponseDto(result.Token, result.RefreshToken));
|
||||
}
|
||||
else
|
||||
|
@ -80,4 +84,16 @@ public class AuthController : ControllerBase
|
|||
return Problem($"An error occurred on the server: {e.Message}", statusCode: StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetJwtCookie(string token)
|
||||
{
|
||||
var cookieOptions = new CookieOptions
|
||||
{
|
||||
HttpOnly = true,
|
||||
Secure = _apiSettings.RunningEnvironment == Enums.RunningEnvironment.Production,
|
||||
SameSite = SameSiteMode.Strict,
|
||||
Expires = DateTimeOffset.UtcNow.AddHours(2)
|
||||
};
|
||||
Response.Cookies.Append("token", token, cookieOptions);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
namespace Guestbooky.API.Enums;
|
||||
|
||||
public enum RunningEnvironment
|
||||
{
|
||||
Unknown = 0,
|
||||
Development,
|
||||
Production
|
||||
}
|
|
@ -1,11 +1,13 @@
|
|||
using Guestbooky.Application.DependencyInjection;
|
||||
using Guestbooky.Infrastructure.DependencyInjection;
|
||||
using Guestbooky.Infrastructure.Environment;
|
||||
using Guestbooky.API.Configurations;
|
||||
using Guestbooky.API.Enums;
|
||||
using Guestbooky.API.Validations;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System.Text;
|
||||
using Serilog;
|
||||
using Guestbooky.API.Validations;
|
||||
|
||||
namespace Guestbooky.API
|
||||
{
|
||||
|
@ -74,9 +76,10 @@ namespace Guestbooky.API
|
|||
var corsOrigins = builder.Configuration[Constants.CORS_ORIGINS]?.Split(',') ?? Array.Empty<string>();
|
||||
cfg.AddPolicy(name: "local", policy =>
|
||||
{
|
||||
policy.WithExposedHeaders("Content-Range", "Accept-Ranges")
|
||||
policy.WithExposedHeaders("Content-Range", "Accept-Ranges", "Set-Cookie")
|
||||
.WithOrigins(corsOrigins)
|
||||
.AllowAnyHeader()
|
||||
.AllowCredentials()
|
||||
.WithMethods("GET", "POST", "DELETE", "OPTIONS");
|
||||
});
|
||||
});
|
||||
|
@ -86,7 +89,11 @@ namespace Guestbooky.API
|
|||
options.InvalidModelStateResponseFactory = InvalidModelStateResponseFactory.DefaultInvalidModelStateResponse;
|
||||
});
|
||||
|
||||
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||
builder.Services.AddAuthentication(o =>
|
||||
{
|
||||
o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
})
|
||||
.AddJwtBearer(o =>
|
||||
{
|
||||
o.RequireHttpsMetadata = false;
|
||||
|
@ -102,12 +109,22 @@ namespace Guestbooky.API
|
|||
ValidateLifetime = true,
|
||||
ClockSkew = TimeSpan.Zero
|
||||
};
|
||||
o.Events = new JwtBearerEvents
|
||||
{
|
||||
OnMessageReceived = context =>
|
||||
{
|
||||
context.Token = context.Request.Cookies["token"];
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
builder.Services.AddInfrastructure(builder.Configuration);
|
||||
builder.Services.AddApplication();
|
||||
|
||||
builder.Services.AddSingleton(new APISettings(){ RunningEnvironment = GetRunningEnvironment(builder.Configuration["ASPNETCORE_ENVIRONMENT"]!) });
|
||||
|
||||
|
||||
if (builder.Environment.IsDevelopment())
|
||||
{
|
||||
|
@ -170,5 +187,12 @@ namespace Guestbooky.API
|
|||
_ => conf.MinimumLevel.Information()
|
||||
};
|
||||
|
||||
public static RunningEnvironment GetRunningEnvironment(string env) => env.ToUpper() switch
|
||||
{
|
||||
"DEVELOPMENT" => RunningEnvironment.Development,
|
||||
"PRODUCTION" => RunningEnvironment.Production,
|
||||
_ => RunningEnvironment.Unknown
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ namespace Guestbooky.Infrastructure.Persistence.Repositories
|
|||
var messageDtos = await _messages.Find(_ => true)
|
||||
.SortBy(x => x.Timestamp)
|
||||
.Skip((int?)offset)
|
||||
.Limit(50)
|
||||
.Limit(10)
|
||||
.ToCursorAsync(cancellationToken);
|
||||
return messageDtos.ToEnumerable().Select(MapToDomainModel).ToArray();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue