Skip to content

Commit

Permalink
add email confirmation feature
Browse files Browse the repository at this point in the history
fixes #1056
  • Loading branch information
iammukeshm committed Feb 22, 2025
1 parent 1b91582 commit 563a9e2
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ public async Task<TokenResponse> GenerateTokenAsync(TokenGenerationCommand reque
throw new UnauthorizedException("user is deactivated");
}

if (!user.EmailConfirmed)
{
throw new UnauthorizedException("email not confirmed");
}

if (currentTenant.Id != TenantConstants.Root.Id)
{
if (!currentTenant.IsActive)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using FSH.Framework.Core.Identity.Users.Abstractions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;

namespace FSH.Framework.Infrastructure.Identity.Users.Endpoints;
public static class ConfirmEmailEndpoint
{
internal static RouteHandlerBuilder MapConfirmEmailEndpoint(this IEndpointRouteBuilder endpoints)
{
return endpoints.MapGet("/confirm-email", (string userId, string code, string tenant, IUserService service) =>
{
return service.ConfirmEmailAsync(userId, code, tenant, default);
})
.WithName(nameof(ConfirmEmailEndpoint))
.WithSummary("confirm user email")
.WithDescription("confirm user email")
.AllowAnonymous();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public static IEndpointRouteBuilder MapUserEndpoints(this IEndpointRouteBuilder
app.MapAssignRolesToUserEndpoint();
app.MapGetUserRolesEndpoint();
app.MapGetUserAuditTrailEndpoint();
app.MapConfirmEmailEndpoint();
return app;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,22 @@ private void EnsureValidTenant()
}
}

public Task<string> ConfirmEmailAsync(string userId, string code, string tenant, CancellationToken cancellationToken)
public async Task<string> ConfirmEmailAsync(string userId, string code, string tenant, CancellationToken cancellationToken)
{
throw new NotImplementedException();
EnsureValidTenant();

var user = await userManager.Users
.Where(u => u.Id == userId && !u.EmailConfirmed)
.FirstOrDefaultAsync(cancellationToken);

_ = user ?? throw new FshException("An error occurred while confirming E-Mail.");

code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code));
var result = await userManager.ConfirmEmailAsync(user, code);

return result.Succeeded
? string.Format("Account Confirmed for E-Mail {0}. You can now use the /api/tokens endpoint to generate JWT.", user.Email)
: throw new FshException(string.Format("An error occurred while confirming {0}", user.Email));
}

public Task<string> ConfirmPhoneNumberAsync(string userId, string code)
Expand Down Expand Up @@ -111,7 +124,8 @@ public async Task<RegisterUserResponse> RegisterAsync(RegisterUserCommand reques
UserName = request.UserName,
PhoneNumber = request.PhoneNumber,
IsActive = true,
EmailConfirmed = true
EmailConfirmed = false,
PhoneNumberConfirmed = false,
};

// register user
Expand Down
8 changes: 8 additions & 0 deletions src/api/framework/Infrastructure/Tenant/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ public static IServiceCollection ConfigureMultitenancy(this IServiceCollection s
})
.WithClaimStrategy(FshClaims.Tenant)
.WithHeaderStrategy(TenantConstants.Identifier)
.WithDelegateStrategy(async context =>
{
if (context is not HttpContext httpContext)
return null;
if (!httpContext.Request.Query.TryGetValue("tenant", out var tenantIdentifier) || string.IsNullOrEmpty(tenantIdentifier))
return null;
return await Task.FromResult(tenantIdentifier.ToString());
})
.WithDistributedCacheStore(TimeSpan.FromMinutes(60))
.WithEFCoreStore<TenantDbContext, FshTenantInfo>();
services.AddScoped<ITenantService, TenantService>();
Expand Down
6 changes: 3 additions & 3 deletions src/api/server/appsettings.Development.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"DatabaseOptions": {
"Provider": "postgresql",
"ConnectionString": "Server=localhost;Database=fullstackhero;Port=5432;User Id=admin;Password=admin;"
"ConnectionString": "Server=192.168.1.110;Database=fsh;User Id=postgres;Password=password"
},
"OriginOptions": {
"OriginUrl": "https://localhost:7000"
Expand All @@ -23,8 +23,8 @@
"From": "[email protected]",
"Host": "smtp.ethereal.email",
"Port": 587,
"UserName": "sherman.oconnell47@ethereal.email",
"Password": "KbuTCFv4J6Fy7256vh",
"UserName": "ruth.ruecker@ethereal.email",
"Password": "wygzuX6kpcK6AfDJcd",
"DisplayName": "Mukesh Murugan"
},
"CorsOptions": {
Expand Down
4 changes: 2 additions & 2 deletions src/api/server/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
"From": "[email protected]",
"Host": "smtp.ethereal.email",
"Port": 587,
"UserName": "sherman.oconnell47@ethereal.email",
"Password": "KbuTCFv4J6Fy7256vh",
"UserName": "ruth.ruecker@ethereal.email",
"Password": "wygzuX6kpcK6AfDJcd",
"DisplayName": "Mukesh Murugan"
},
"CorsOptions": {
Expand Down

0 comments on commit 563a9e2

Please sign in to comment.