Skip to content

Commit 6c68c0b

Browse files
committed
Get Account Info endpoint
1 parent 8aaead1 commit 6c68c0b

18 files changed

Lines changed: 161 additions & 5 deletions

File tree

Directory.Packages.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
<PackageVersion Include="MassTransit.EntityFrameworkCore" Version="8.0.11" />
2121
<PackageVersion Include="MassTransit.RabbitMQ" Version="8.0.11" />
2222
<PackageVersion Include="MediatR" Version="13.1.0" />
23+
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.22" />
2324
<PackageVersion Include="Microsoft.AspNetCore.Identity" Version="2.3.1" />
2425
<PackageVersion Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.22" />
2526
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="8.0.21" />
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using Kairos.Account.Infra;
2+
using Kairos.Shared.Contracts;
3+
using Kairos.Shared.Contracts.Account;
4+
using Kairos.Shared.Contracts.Account.GetAccountInfo;
5+
using MediatR;
6+
using Microsoft.Extensions.Logging;
7+
8+
namespace Kairos.Account.Business.UseCases;
9+
10+
internal sealed class GetAccountInfoUseCase(
11+
ILogger<GetAccountInfoUseCase> logger,
12+
AccountContext db) : IRequestHandler<GetAccountInfoQuery, Output<AccountInfo>>
13+
{
14+
public async Task<Output<AccountInfo>> Handle(GetAccountInfoQuery input, CancellationToken cancellationToken)
15+
{
16+
try
17+
{
18+
var account = await db.Investors.FindAsync(input.Id, cancellationToken);
19+
20+
if (account is null)
21+
{
22+
logger.LogWarning(
23+
"Attempted to access non-existent account with ID {AccountId}",
24+
input.Id);
25+
return Output<AccountInfo>.PolicyViolation(["Conta não encontrada."]);
26+
}
27+
28+
return Output<AccountInfo>.Ok(new AccountInfo(
29+
account.Id,
30+
account.Name,
31+
account.Birthdate,
32+
account.Gender,
33+
account.PhoneNumber ?? string.Empty,
34+
account.Document,
35+
account.Email!,
36+
Address: string.Empty
37+
));
38+
}
39+
catch (Exception ex)
40+
{
41+
logger.LogError(ex, "An unexpected error occurred.");
42+
return Output<AccountInfo>.UnexpectedError([
43+
"Um erro inesperado ocorreu...",
44+
ex.Message]);
45+
}
46+
}
47+
}

src/Account/DependencyInjection.cs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
using System.Reflection;
2+
using System.Text;
23
using Kairos.Account.Configuration;
34
using Kairos.Account.Domain;
45
using Kairos.Account.Infra;
56
using Kairos.Account.Infra.Consumers;
67
using Kairos.Shared.Contracts.Account;
78
using MassTransit;
9+
using Microsoft.AspNetCore.Authentication.JwtBearer;
810
using Microsoft.AspNetCore.Identity;
911
using Microsoft.EntityFrameworkCore;
1012
using Microsoft.Extensions.Configuration;
1113
using Microsoft.Extensions.DependencyInjection;
14+
using Microsoft.Extensions.Options;
15+
using Microsoft.IdentityModel.Tokens;
1216

1317
namespace Kairos.Account;
1418

@@ -21,6 +25,7 @@ public static IServiceCollection AddAccount(
2125
services.Configure<Settings>(config);
2226

2327
return services
28+
.AddAuth()
2429
.AddIdentity(config)
2530
.AddMediatR(cfg =>
2631
{
@@ -89,4 +94,45 @@ static IServiceCollection AddIdentity(
8994

9095
return services;
9196
}
97+
98+
static IServiceCollection AddAuth(this IServiceCollection services)
99+
{
100+
var jwt = services
101+
.BuildServiceProvider()
102+
.GetRequiredService<IOptions<Settings>>()
103+
.Value.Jwt;
104+
105+
services
106+
.AddAuthentication(o =>
107+
{
108+
o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
109+
o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
110+
})
111+
.AddJwtBearer(o =>
112+
{
113+
o.TokenValidationParameters = new TokenValidationParameters
114+
{
115+
ValidateIssuer = true,
116+
ValidateAudience = true,
117+
ValidateLifetime = true,
118+
ValidateIssuerSigningKey = true,
119+
ValidIssuer = jwt.Issuer,
120+
ValidAudience = jwt.Audience,
121+
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwt.Secret))
122+
};
123+
124+
o.Events = new JwtBearerEvents
125+
{
126+
OnMessageReceived = context =>
127+
{
128+
context.Token = context.Request.Cookies[jwt.CookieName];
129+
return Task.CompletedTask;
130+
}
131+
};
132+
});
133+
134+
services.AddAuthorization();
135+
136+
return services;
137+
}
92138
}

src/Account/Domain/Investor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ internal sealed class Investor : KairosAccount
1212
public string Name { get; private set; }
1313
public string Document { get; private set; }
1414
public DateTime Birthdate { get; private set; }
15-
public Gender Gender { get; private set; }
15+
public Gender Gender { get; }
1616
public PersonType Type { get; private set; }
1717

1818
Investor(
File renamed without changes.
File renamed without changes.

src/Account/Kairos.Account.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
1212
</ItemGroup>
1313
<ItemGroup>
14+
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" />
1415
<PackageReference Include="Microsoft.AspNetCore.Identity" />
1516
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" />
1617
</ItemGroup>

src/Gateway/DependencyInjection.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,14 @@ public static IServiceCollection AddGateway(
2020
IConfiguration configuration)
2121
{
2222
services
23-
.AddAuthorization()
2423
.AddHealthChecksUI(options =>
2524
{
2625
options.SetEvaluationTimeInSeconds(30);
2726
options.AddHealthCheckEndpoint("Kairos", "/health/ready");
2827
})
2928
.AddInMemoryStorage();
3029

31-
services
32-
.AddCarter()
33-
.AddAuthentication();
30+
services.AddCarter();
3431

3532
return services
3633
.AddMapper()

src/Gateway/Filters/ResponseFormatter.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ internal sealed class ResponseFormatter(ILogger<ResponseFormatter> logger) : IEn
2929
OutputStatus.InvalidInput => StatusCodes.Status400BadRequest,
3030
OutputStatus.NotFound => StatusCodes.Status404NotFound,
3131
OutputStatus.PolicyViolation => StatusCodes.Status422UnprocessableEntity,
32+
OutputStatus.CredentialsRequired => StatusCodes.Status401Unauthorized,
3233
_ => StatusCodes.Status500InternalServerError,
3334
};
3435

src/Gateway/Modules/Account/AccountModule.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
using System.Security.Claims;
12
using Carter;
23
using Kairos.Account.Configuration;
4+
using Kairos.Gateway.Filters;
35
using Kairos.Gateway.Modules.Account.Request;
46
using Kairos.Shared.Contracts;
57
using Kairos.Shared.Contracts.Account;
8+
using Kairos.Shared.Contracts.Account.GetAccountInfo;
69
using MediatR;
710
using Microsoft.AspNetCore.Mvc;
811
using Microsoft.Extensions.Options;
@@ -120,5 +123,32 @@ public override void AddRoutes(IEndpointRouteBuilder app)
120123
e.Responses["500"].Description = "An unexpected server error occurred.";
121124
return e;
122125
});
126+
127+
app.MapGet("/me",
128+
async (HttpContext ctx) =>
129+
{
130+
var accountIdValue = ctx.User.FindFirstValue(ClaimTypes.NameIdentifier);
131+
132+
if (long.TryParse(accountIdValue, out var accountId) is false)
133+
{
134+
return Output.CredentialsRequired(["Acesse sua conta para visualizar os dados cadastrais."]);
135+
}
136+
137+
var output = await _mediator.Send(new GetAccountInfoQuery(accountId));
138+
139+
return output;
140+
})
141+
.RequireAuthorization()
142+
.WithSummary("Get the authenticated account's data")
143+
.Produces<Response<AccountInfo>>(StatusCodes.Status200OK)
144+
.Produces<Response>(StatusCodes.Status401Unauthorized)
145+
.Produces<Response>(StatusCodes.Status500InternalServerError)
146+
.WithOpenApi(e =>
147+
{
148+
e.Responses["200"].Description = "Returns the account details for the authenticated user.";
149+
e.Responses["401"].Description = "Unauthorized if the auth cookie is missing or invalid.";
150+
e.Responses["500"].Description = "An unexpected server error occurred.";
151+
return e;
152+
});
123153
}
124154
}

0 commit comments

Comments
 (0)