@@ -1,52 +1,47 @@
using Microsoft.AspNetCore.Identity ;
// src/Webshop.Application/Services/Auth/AuthService.cs
using Microsoft.AspNetCore.Identity ;
using Microsoft.Extensions.Configuration ;
using Microsoft.IdentityModel.Tokens ;
using Resend ;
using System ;
using System.IdentityModel.Tokens.Jwt ;
using System.Linq ;
using System.Security.Claims ;
using System.Text ;
using Webshop.Application.DTOs.Auth ;
using Webshop.Domain.Entities ;
using Webshop.Infrastructure.Data ;
using Webshop.Domain.Identity ;
using Resend ;
using System.Threading.Tasks ;
using System.Web ;
using System.Net.Mail ;
using Webshop.Application.DTOs.Auth ;
using Webshop.Domain.Identity ;
using Webshop.Infrastructure.Data ;
using Webshop.Application ;
namespace Webshop.Application.Services.Auth
{
public class AuthService : IAuthService
{
private readonly UserManager < ApplicationUser > _userManager ;
private readonly SignInManager < ApplicationUser > _signInManager ;
private readonly IConfiguration _configuration ;
private readonly RoleManager < IdentityRole > _roleManager ;
private readonly IResend _resend ;
private readonly ApplicationDbContext _context ; // << NEU: Deklaration >>
private readonly ApplicationDbContext _context ;
public AuthService (
UserManager < ApplicationUser > userManager ,
SignInManager < ApplicationUser > signInManager ,
IConfiguration configuration ,
RoleManager < IdentityRole > roleManager ,
IResend resend ,
ApplicationDbContext context ) // << NEU: DbContext im Konstruktor injizieren >>
ApplicationDbContext context )
{
_userManager = userManager ;
_signInManager = signInManager ;
_configuration = configuration ;
_roleManager = roleManager ;
_resend = resend ;
_context = context ; // << NEU: Initialisierung >>
_context = context ;
}
public async Task < AuthResponseDto > RegisterUserAsync ( RegisterRequestDto request )
public async Task < ServiceResult > RegisterUserAsync ( RegisterRequestDto request )
{
var existingUser = await _userManager . FindByEmailAsync ( request . Email ) ;
if ( existingUser ! = null )
var userExists = await _userManager . FindByEmailAsync ( request . Email ) ;
if ( userExists ! = null )
{
return new AuthResponseDto { IsAuthSuccessful = false , ErrorMessage = "E-Mail ist bereits registriert." } ;
return ServiceResult . Fail ( ServiceResultType . InvalidInput , "Ein Benutzer mit dieser E-Mail-Adresse existiert bereits." ) ;
}
var user = new ApplicationUser { Email = request . Email , UserName = request . Email , CreatedDate = DateTimeOffset . UtcNow } ;
@@ -55,121 +50,41 @@ namespace Webshop.Application.Services.Auth
if ( ! result . Succeeded )
{
var errors = string . Join ( " " , result . Errors . Select ( e = > e . Description ) ) ;
return new AuthResponseDto { IsAuthSuccessful = false , ErrorMessage = errors } ;
return ServiceResult . Fail ( ServiceResultType . Failure , errors ) ;
}
if ( ! await _roleManager . RoleExistsAsync ( "Customer" ) )
{
await _roleManager . CreateAsync ( new IdentityRole ( "Customer" ) ) ;
}
await _userManager . AddToRoleAsync ( user , "Customer" ) ;
// << NEU: HIER WIRD DAS CUSTOMER-PROFIL ERSTELLT UND GESPEICHERT >>
var customerProfile = new Webshop . Domain . Entities . Customer
var customerProfile = new Domain . Entities . Customer
{
Id = Guid . NewGuid ( ) ,
AspNetUserId = user . Id , // Verknüpfung zum ApplicationUser
Fir stName = request . Fir stName ? ? string . Empty , // Vom Request-DTO
LastName = request . LastName ? ? string . Empty , // Vom Request-DTO
AspNetUser Id = user . Id ,
FirstName = request . FirstName ,
La stName = request . La stName
} ;
_context . Customers . Add ( customerProfile ) ;
await _context . SaveChangesAsync ( ) ; // Speichere das neue Kundenprofil
// << ENDE NEUER TEIL >>
await _context . SaveChangesAsync ( ) ;
await SendEmailConfirmationEmail ( user ) ;
return new AuthResponseDto
{
IsAuthSuccessful = true ,
ErrorMessage = "Registrierung erfolgreich. Bitte bestätigen Sie Ihre E-Mail-Adresse." ,
Token = "" ,
UserId = user . Id ,
Email = user . Email ,
Roles = ( await _userManager . GetRolesAsync ( user ) ) . ToList ( )
} ;
return ServiceResult . Ok ( ) ;
}
public async Task < ( bool Success , string ErrorMessage ) > ConfirmEmailAsync ( string userId , string token )
{
var user = await _userManager . FindByIdAsync ( userId ) ;
if ( user = = null )
{
return ( false , "Benutzer nicht gefunden." ) ;
}
var result = await _userManager . ConfirmEmailAsync ( user , HttpUtility . UrlDecode ( token ) ) ;
if ( ! result . Succeeded )
{
var errors = string . Join ( " " , result . Errors . Select ( e = > e . Description ) ) ;
return ( false , $"E-Mail-Bestätigung fehlgeschlagen: {errors}" ) ;
}
return ( true , "E-Mail-Adresse erfolgreich bestätigt." ) ;
}
public async Task < ( bool Success , string ErrorMessage ) > ResendEmailConfirmationAsync ( string email )
{
var user = await _userManager . FindByEmailAsync ( email ) ;
if ( user = = null )
{
return ( false , "Benutzer nicht gefunden oder E-Mail existiert nicht." ) ;
}
if ( await _userManager . IsEmailConfirmedAsync ( user ) )
{
return ( false , "E-Mail-Adresse ist bereits bestätigt." ) ;
}
await SendEmailConfirmationEmail ( user ) ;
return ( true , "Bestätigungs-E-Mail wurde erneut gesendet. Bitte prüfen Sie Ihr Postfach." ) ;
}
private async Task SendEmailConfirmationEmail ( ApplicationUser user ) // << WICHTIG: ApplicationUser als Typ >>
{
var token = await _userManager . GenerateEmailConfirmationTokenAsync ( user ) ;
var encodedToken = HttpUtility . UrlEncode ( token ) ;
var baseUrl = _configuration [ "App:BaseUrl" ] ; // Von appsettings.json oder Umgebungsvariablen
var confirmationLink = $"{baseUrl}/api/v1/auth/confirm-email?userId={user.Id}&token={encodedToken}" ;
var message = new EmailMessage ( ) ;
message . From = "Your Webshop <onboarding@resend.dev>" ; // << ANPASSEN: Absender-E-Mail und Domain >>
message . To . Add ( user . Email ) ;
message . Subject = "Bestätigen Sie Ihre E-Mail-Adresse für Your Webshop" ;
message . HtmlBody = $@"
<h1>Willkommen bei Your Webshop!</h1>
<p>Bitte klicken Sie auf den folgenden Link, um Ihre E-Mail-Adresse zu bestätigen:</p>
<p><a href=""{confirmationLink}"">{confirmationLink}</a></p>
<p>Vielen Dank!</p>" ;
await _resend . EmailSendAsync ( message ) ;
}
public async Task < AuthResponseDto > LoginUserAsync ( LoginRequestDto request )
public async Task < ServiceResult < AuthResponseDto > > LoginUserAsync ( LoginRequestDto request )
{
var user = await _userManager . FindByEmailAsync ( request . Email ) ;
if ( user = = null )
if ( user = = null | | ! await _userManager . CheckPasswordAsync ( user , request . Password ) )
{
return new AuthResponseDto { IsAuthSuccessful = false , ErrorMessage = "Ungültige Anmeldeinformationen." } ;
return ServiceResult . Fail < AuthResponseDto > ( ServiceResultType . Unauthorized , "Ungültige Anmeldeinformationen." ) ;
}
// << NEU: Prüfen, ob E-Mail bestätigt ist >>
if ( ! await _userManager . IsEmailConfirmedAsync ( user ) )
{
return new AuthResponseDto { IsAuthSuccessful = false , ErrorMessage = "E-Mail-Adresse wurde noch nicht bestätigt. Bitte prüfen Sie Ihr Postfach." } ;
}
var signInResult = await _signInManager . CheckPasswordSignInAsync ( user , request . Password , false ) ;
if ( ! signInResult . Succeeded )
{
return new AuthResponseDto { IsAuthSuccessful = false , ErrorMessage = "Ungültige Anmeldeinformationen." } ;
return ServiceResult . Fail < AuthResponseDto > ( ServiceResultType . Unauthorized , "E-Mail-Adresse wurde noch nicht bestätigt." ) ;
}
var roles = await _userManager . GetRolesAsync ( user ) ;
var token = await GenerateJwtToken ( user , roles ) ;
var token = GenerateJwtToken ( user , roles ) ;
return new AuthResponseDto
var response = new AuthResponseDto
{
IsAuthSuccessful = true ,
Token = token ,
@@ -177,34 +92,117 @@ namespace Webshop.Application.Services.Auth
Email = user . Email ,
Roles = roles . ToList ( )
} ;
return ServiceResult . Ok ( response ) ;
}
public async Task < AuthResponseDto > LoginAdminAsync ( LoginRequestDto request )
public async Task < ServiceResult < AuthResponseDto> > LoginAdminAsync ( LoginRequestDto request )
{
var authResponse = await LoginUserAsync ( request ) ;
if ( ! authResponse . IsAuth Successful )
var loginResult = await LoginUserAsync ( request ) ;
if ( loginResult . Type ! = ServiceResultType . Success)
{
return authResponse ;
return loginResult ;
}
var user = await _userManager . FindByEmailAsync ( request . Email ) ;
if ( user = = null | | ! await _userManager . IsInRoleAsync ( user , "Admin" ) )
{
return new AuthResponseDto { IsAuthSuccessful = false , ErrorMessage = "Keine Berechtigung." } ;
return ServiceResult . Fail < AuthResponseDto > ( ServiceResultType . Forbidden , "Keine Berechtigung für den Admin-Zugang." ) ;
}
return authResponse ;
return loginResult ;
}
private async Task < string > GenerateJwtToken ( ApplicationUser user , IList < string > roles ) // << WICHTIG: ApplicationUser >>
public async Task < ServiceResult > ConfirmEmailAsync ( string userId , string token )
{
var user = await _userManager . FindByIdAsync ( userId ) ;
if ( user = = null )
{
return ServiceResult . Fail ( ServiceResultType . NotFound , "Benutzer nicht gefunden." ) ;
}
var result = await _userManager . ConfirmEmailAsync ( user , HttpUtility . UrlDecode ( token ) ) ;
return result . Succeeded ? ServiceResult . Ok ( ) : ServiceResult . Fail ( ServiceResultType . Failure , "E-Mail-Bestätigung fehlgeschlagen." ) ;
}
public async Task < ServiceResult > ResendEmailConfirmationAsync ( string email )
{
var user = await _userManager . FindByEmailAsync ( email ) ;
if ( user = = null )
{
// Aus Sicherheitsgründen nicht verraten, ob die E-Mail existiert
return ServiceResult . Ok ( ) ;
}
if ( await _userManager . IsEmailConfirmedAsync ( user ) )
{
return ServiceResult . Fail ( ServiceResultType . InvalidInput , "E-Mail-Adresse ist bereits bestätigt." ) ;
}
await SendEmailConfirmationEmail ( user ) ;
return ServiceResult . Ok ( ) ;
}
public async Task < ServiceResult > ForgotPasswordAsync ( ForgotPasswordRequestDto request )
{
var user = await _userManager . FindByEmailAsync ( request . Email ) ;
if ( user = = null | | ! ( await _userManager . IsEmailConfirmedAsync ( user ) ) )
{
return ServiceResult . Ok ( ) ;
}
var token = await _userManager . GeneratePasswordResetTokenAsync ( user ) ;
var encodedToken = HttpUtility . UrlEncode ( token ) ;
var clientUrl = _configuration [ "App:ClientUrl" ] ! ;
var resetLink = $"{clientUrl}/reset-password?email={HttpUtility.UrlEncode(request.Email)}&token={encodedToken}" ;
// << KORREKTUR: EmailMessage verwenden >>
var message = new EmailMessage ( ) ;
message . To . Add ( request . Email ) ;
message . From = _configuration [ "Resend:FromEmail" ] ! ;
message . Subject = "Anleitung zum Zurücksetzen Ihres Passworts" ;
message . HtmlBody = $"<h1>Passwort zurücksetzen</h1><p>Bitte setzen Sie Ihr Passwort zurück, indem Sie auf diesen Link klicken: <a href='{resetLink}'>Passwort zurücksetzen</a></p>" ;
await _resend . EmailSendAsync ( message ) ;
return ServiceResult . Ok ( ) ;
}
public async Task < ServiceResult > ResetPasswordAsync ( ResetPasswordDto request )
{
var user = await _userManager . FindByEmailAsync ( request . Email ) ;
if ( user = = null )
{
return ServiceResult . Fail ( ServiceResultType . InvalidInput , "Fehler beim Zurücksetzen des Passworts." ) ;
}
var result = await _userManager . ResetPasswordAsync ( user , HttpUtility . UrlDecode ( request . Token ) , request . NewPassword ) ;
return result . Succeeded
? ServiceResult . Ok ( )
: ServiceResult . Fail ( ServiceResultType . InvalidInput , string . Join ( " " , result . Errors . Select ( e = > e . Description ) ) ) ;
}
private async Task SendEmailConfirmationEmail ( ApplicationUser user )
{
var token = await _userManager . GenerateEmailConfirmationTokenAsync ( user ) ;
var encodedToken = HttpUtility . UrlEncode ( token ) ;
var clientUrl = _configuration [ "App:ClientUrl" ] ! ;
var confirmationLink = $"{clientUrl}/confirm-email?userId={user.Id}&token={encodedToken}" ;
// << KORREKTUR: EmailMessage verwenden >>
var message = new EmailMessage ( ) ;
message . To . Add ( user . Email ) ;
message . From = _configuration [ "Resend:FromEmail" ] ! ;
message . Subject = "Bestätigen Sie Ihre E-Mail-Adresse" ;
message . HtmlBody = $"<h1>Willkommen!</h1><p>Bitte bestätigen Sie Ihre E-Mail-Adresse, indem Sie auf diesen Link klicken: <a href='{confirmationLink}'>Bestätigen</a></p>" ;
await _resend . EmailSendAsync ( message ) ;
}
private string GenerateJwtToken ( ApplicationUser user , IList < string > roles )
{
var claims = new List < Claim >
{
new Claim ( JwtRegisteredClaimNames . Sub , user . Id ) ,
new Claim ( JwtRegisteredClaimNames . Jti , Guid . NewGuid ( ) . ToString ( ) ) ,
new Claim ( JwtRegisteredClaimNames . Email , user . Email ! )
// Optional: Fügen Sie Custom Claims von ApplicationUser hinzu
// new Claim("created_date", user.CreatedDate.ToString("o"))
} ;
foreach ( var role in roles )
@@ -227,6 +225,5 @@ namespace Webshop.Application.Services.Auth
return new JwtSecurityTokenHandler ( ) . WriteToken ( token ) ;
}
}
}
}