wip
This commit is contained in:
parent
0dc41337da
commit
14fd359ea8
28 changed files with 156 additions and 52 deletions
53
Femto.Api/Auth/SessionAuthenticationHandler.cs
Normal file
53
Femto.Api/Auth/SessionAuthenticationHandler.cs
Normal file
|
@ -0,0 +1,53 @@
|
|||
using System.Security.Claims;
|
||||
using System.Text.Encodings.Web;
|
||||
using Femto.Api.Sessions;
|
||||
using Femto.Common;
|
||||
using Femto.Modules.Auth.Application;
|
||||
using Femto.Modules.Auth.Application.Commands.ValidateSession;
|
||||
using Femto.Modules.Auth.Errors;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Femto.Api.Auth;
|
||||
|
||||
internal class SessionAuthenticationHandler(
|
||||
IOptionsMonitor<AuthenticationSchemeOptions> options,
|
||||
ILoggerFactory logger,
|
||||
UrlEncoder encoder,
|
||||
IAuthenticationModule authModule,
|
||||
CurrentUserContext currentUserContext
|
||||
) : AuthenticationHandler<AuthenticationSchemeOptions>(options, logger, encoder)
|
||||
{
|
||||
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||
{
|
||||
var sessionId = this.Request.Cookies["session"];
|
||||
if (string.IsNullOrWhiteSpace(sessionId))
|
||||
return AuthenticateResult.NoResult();
|
||||
|
||||
try
|
||||
{
|
||||
var result = await authModule.PostCommand(new ValidateSessionCommand(sessionId));
|
||||
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new(ClaimTypes.Name, result.Username),
|
||||
new("sub", result.UserId.ToString()),
|
||||
new("user_id", result.UserId.ToString()),
|
||||
};
|
||||
|
||||
var identity = new ClaimsIdentity(claims, this.Scheme.Name);
|
||||
var principal = new ClaimsPrincipal(identity);
|
||||
|
||||
this.Context.SetSession(result.Session);
|
||||
currentUserContext.CurrentUser = new CurrentUser(result.UserId, result.Username);
|
||||
|
||||
return AuthenticateResult.Success(
|
||||
new AuthenticationTicket(principal, this.Scheme.Name)
|
||||
);
|
||||
}
|
||||
catch (InvalidSessionError)
|
||||
{
|
||||
return AuthenticateResult.Fail("Invalid session");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,8 +22,8 @@ public class AuthController(IAuthenticationModule authModule) : ControllerBase
|
|||
return new LoginResponse(result.UserId, result.Username);
|
||||
}
|
||||
|
||||
[HttpPost("signup")]
|
||||
public async Task<ActionResult<SignupResponse>> Signup([FromBody] SignupRequest request)
|
||||
[HttpPost("register")]
|
||||
public async Task<ActionResult<RegisterResponse>> Register([FromBody] RegisterRequest request)
|
||||
{
|
||||
var result = await authModule.PostCommand(
|
||||
new RegisterCommand(request.Username, request.Password)
|
||||
|
@ -31,7 +31,7 @@ public class AuthController(IAuthenticationModule authModule) : ControllerBase
|
|||
|
||||
HttpContext.SetSession(result.Session);
|
||||
|
||||
return new SignupResponse(result.UserId, result.Username);
|
||||
return new RegisterResponse(result.UserId, result.Username);
|
||||
}
|
||||
|
||||
[HttpPost("delete-session")]
|
||||
|
|
3
Femto.Api/Controllers/Auth/RegisterRequest.cs
Normal file
3
Femto.Api/Controllers/Auth/RegisterRequest.cs
Normal file
|
@ -0,0 +1,3 @@
|
|||
namespace Femto.Api.Controllers.Auth;
|
||||
|
||||
public record RegisterRequest(string Username, string Password, string SignupCode, string? Email);
|
3
Femto.Api/Controllers/Auth/RegisterResponse.cs
Normal file
3
Femto.Api/Controllers/Auth/RegisterResponse.cs
Normal file
|
@ -0,0 +1,3 @@
|
|||
namespace Femto.Api.Controllers.Auth;
|
||||
|
||||
public record RegisterResponse(Guid UserId, string Username);
|
|
@ -1,3 +0,0 @@
|
|||
namespace Femto.Api.Controllers.Auth;
|
||||
|
||||
public record SignupRequest(string Username, string Password, string SignupCode, string? Email);
|
|
@ -1,3 +0,0 @@
|
|||
namespace Femto.Api.Controllers.Auth;
|
||||
|
||||
public record SignupResponse(Guid UserId, string Username);
|
|
@ -4,6 +4,7 @@ using Femto.Modules.Blog.Application;
|
|||
using Femto.Modules.Blog.Application.Commands.CreatePost;
|
||||
using Femto.Modules.Blog.Application.Queries.GetPosts;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Femto.Api.Controllers.Posts;
|
||||
|
@ -13,6 +14,7 @@ namespace Femto.Api.Controllers.Posts;
|
|||
public class PostsController(IBlogModule blogModule) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<GetAllPublicPostsResponse>> GetAllPublicPosts(
|
||||
[FromQuery] GetPublicPostsSearchParams searchParams,
|
||||
CancellationToken cancellationToken
|
||||
|
|
8
Femto.Api/CurrentUserContext.cs
Normal file
8
Femto.Api/CurrentUserContext.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
using Femto.Common;
|
||||
|
||||
namespace Femto.Api;
|
||||
|
||||
internal class CurrentUserContext : ICurrentUserContext
|
||||
{
|
||||
public CurrentUser? CurrentUser { get; set; }
|
||||
}
|
|
@ -28,4 +28,8 @@
|
|||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Middleware\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Femto.Api;
|
||||
using Femto.Api.Auth;
|
||||
using Femto.Common;
|
||||
using Femto.Modules.Auth.Application;
|
||||
using Femto.Modules.Blog.Application;
|
||||
using Femto.Modules.Media.Application;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
|
||||
const string CorsPolicyName = "DefaultCorsPolicy";
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
|
@ -20,15 +26,18 @@ builder.Services.InitializeBlogModule(connectionString);
|
|||
builder.Services.InitializeMediaModule(connectionString, blobStorageRoot);
|
||||
builder.Services.InitializeAuthenticationModule(connectionString);
|
||||
|
||||
builder.Services.AddScoped<CurrentUserContext, CurrentUserContext>();
|
||||
builder.Services.AddScoped<ICurrentUserContext>(s => s.GetRequiredService<CurrentUserContext>());
|
||||
|
||||
builder.Services.AddControllers();
|
||||
|
||||
builder.Services.AddCors(options =>
|
||||
{
|
||||
options.AddPolicy(
|
||||
"DefaultCorsPolicy",
|
||||
CorsPolicyName,
|
||||
b =>
|
||||
{
|
||||
b.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin();
|
||||
b.AllowAnyHeader().AllowAnyMethod().WithOrigins("http://localhost:5173");
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -44,9 +53,18 @@ builder
|
|||
options.JsonSerializerOptions.NumberHandling = JsonNumberHandling.AllowReadingFromString;
|
||||
});
|
||||
|
||||
builder
|
||||
.Services.AddAuthentication("SessionAuth")
|
||||
.AddScheme<AuthenticationSchemeOptions, SessionAuthenticationHandler>(
|
||||
"SessionAuth",
|
||||
options => { }
|
||||
);
|
||||
|
||||
builder.Services.AddAuthorization(); // if not already added
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
app.UseCors("DefaultCorsPolicy");
|
||||
app.UseCors(CorsPolicyName);
|
||||
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
|
|
|
@ -12,8 +12,8 @@ internal static class HttpContextSessionExtensions
|
|||
new CookieOptions
|
||||
{
|
||||
HttpOnly = true,
|
||||
Secure = true,
|
||||
SameSite = SameSiteMode.Strict,
|
||||
// Secure = true,
|
||||
// SameSite = SameSiteMode.Strict,
|
||||
Expires = session.Expires,
|
||||
}
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue