135 lines
5.1 KiB
C#
135 lines
5.1 KiB
C#
using Fluxor;
|
|
using Koogle.Application.DTOs;
|
|
using Koogle.Application.Interfaces;
|
|
using Koogle.Infrastructure.Identity;
|
|
using Koogle.Web.Store.AuthState;
|
|
using Microsoft.AspNetCore.Components;
|
|
using Microsoft.AspNetCore.Identity;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
namespace Koogle.Web.Controllers
|
|
{
|
|
/// <summary>
|
|
/// Controller für Authentifizierungsaktionen (Login, Logout)
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// UserManagerService nutzt SignInManager der wiederum nicht in einer SignalR methode funktioniert.
|
|
/// Aus dem Grund werden Login/Logout Aktionen hier im MVC Controller mit einem "normalen" Post-Request abgewickelt.
|
|
/// </remarks>
|
|
[Microsoft.AspNetCore.Mvc.Route("auth")]
|
|
public class AuthController(IDispatcher dispatcher, IUserService userService) : Controller
|
|
{
|
|
private readonly IDispatcher _dispatcher = dispatcher;
|
|
private readonly IUserService _userService = userService;
|
|
|
|
|
|
[HttpPost("login")]
|
|
[ValidateAntiForgeryToken]
|
|
public async Task<IActionResult> Login(
|
|
[FromForm] LoginDto input)
|
|
{
|
|
var returnUrl = string.IsNullOrWhiteSpace(input.ReturnUrl) ? "/" : input.ReturnUrl;
|
|
|
|
var user = await _userService.LoginAsync(input);
|
|
if (user != null)
|
|
{
|
|
return LocalRedirect(returnUrl);
|
|
}
|
|
return LocalRedirect("/account/login?error=true");
|
|
}
|
|
|
|
|
|
[HttpPost("logout")]
|
|
[ValidateAntiForgeryToken]
|
|
public async Task<IActionResult> Logout([FromForm] string? returnUrl = null)
|
|
{
|
|
await _userService.SignOutAsync();
|
|
|
|
_dispatcher.Dispatch(new LogoutCompleteAction());
|
|
|
|
// Nach Logout per Redirect neu laden (neuer Request -> neue Auth-Session)
|
|
returnUrl ??= "/account/login";
|
|
return LocalRedirect(returnUrl);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handles user registration via form POST.
|
|
/// </summary>
|
|
[HttpPost("register")]
|
|
[ValidateAntiForgeryToken]
|
|
public async Task<IActionResult> Register([FromForm] RegisterUserDto input)
|
|
{
|
|
var result = await _userService.RegisterUserAsync(input);
|
|
if (result.Succeeded)
|
|
{
|
|
// If invite token was provided, redirect to join page
|
|
if (!string.IsNullOrWhiteSpace(input.InviteToken))
|
|
{
|
|
return LocalRedirect($"/account/login?registered=true&invite={Uri.EscapeDataString(input.InviteToken)}");
|
|
}
|
|
return LocalRedirect("/account/login?registered=true");
|
|
}
|
|
|
|
// Build error string from IdentityResult
|
|
var errors = string.Join(",", result.Errors.Select(e => e.Code));
|
|
var inviteParam = !string.IsNullOrWhiteSpace(input.InviteToken)
|
|
? $"&invite={Uri.EscapeDataString(input.InviteToken)}"
|
|
: "";
|
|
return LocalRedirect($"/account/register?error={errors}{inviteParam}");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handles password reset request (forgot password).
|
|
/// </summary>
|
|
[HttpPost("forgot-password")]
|
|
[ValidateAntiForgeryToken]
|
|
public async Task<IActionResult> ForgotPassword([FromForm] string email)
|
|
{
|
|
// Always show success to prevent email enumeration
|
|
var token = await _userService.RequestPasswordResetAsync(email);
|
|
|
|
if (token != null)
|
|
{
|
|
// TODO: Send email with reset link
|
|
// For now, log the token for development purposes
|
|
var resetUrl = $"/account/reset-password?email={Uri.EscapeDataString(email)}&token={Uri.EscapeDataString(token)}";
|
|
Console.WriteLine($"[DEV] Password reset link: {resetUrl}");
|
|
}
|
|
|
|
return LocalRedirect("/account/forgot-password?success=true");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handles password reset with token.
|
|
/// </summary>
|
|
[HttpPost("reset-password")]
|
|
[ValidateAntiForgeryToken]
|
|
public async Task<IActionResult> ResetPassword([FromForm] ResetPasswordFormDto input)
|
|
{
|
|
// Validate password confirmation
|
|
if (input.NewPassword != input.ConfirmPassword)
|
|
{
|
|
return LocalRedirect($"/account/reset-password?email={Uri.EscapeDataString(input.Email)}&token={Uri.EscapeDataString(input.Token)}&error=PasswordMismatch");
|
|
}
|
|
|
|
var dto = new ResetPasswordDto
|
|
{
|
|
Email = input.Email,
|
|
Token = input.Token,
|
|
NewPassword = input.NewPassword
|
|
};
|
|
|
|
var result = await _userService.ResetPasswordAsync(dto);
|
|
if (result.Succeeded)
|
|
{
|
|
return LocalRedirect("/account/reset-password?success=true");
|
|
}
|
|
|
|
var errors = string.Join(",", result.Errors.Select(e => e.Code));
|
|
return LocalRedirect($"/account/reset-password?email={Uri.EscapeDataString(input.Email)}&token={Uri.EscapeDataString(input.Token)}&error={errors}");
|
|
}
|
|
}
|
|
|
|
|
|
}
|