diff --git a/crs/CommonComponents/Contracts/Contracts.csproj b/crs/CommonComponents/Contracts/Contracts.csproj index 7521ead..7b5f0d4 100644 --- a/crs/CommonComponents/Contracts/Contracts.csproj +++ b/crs/CommonComponents/Contracts/Contracts.csproj @@ -13,7 +13,7 @@ - + diff --git a/crs/CommonComponents/Contracts/Services/Identity/Identity.proto b/crs/CommonComponents/Contracts/Services/Identity/identity.v1.proto similarity index 71% rename from crs/CommonComponents/Contracts/Services/Identity/Identity.proto rename to crs/CommonComponents/Contracts/Services/Identity/identity.v1.proto index 2be51d9..8d6cb82 100644 --- a/crs/CommonComponents/Contracts/Services/Identity/Identity.proto +++ b/crs/CommonComponents/Contracts/Services/Identity/identity.v1.proto @@ -1,18 +1,16 @@ syntax = "proto3"; -option csharp_namespace = "Contracts.Services.Identity"; - -package identity; +package identity.v1; service IdentityService { - rpc GetUser(GetUserRequest) returns (User); + rpc GetUserInfo(GetUserRequest) returns (UserInfo); } message GetUserRequest { string id = 1; } -message User { +message UserInfo { string user_id = 1; string email = 2; string first_name = 3; diff --git a/crs/Docker/docker-compose.override.yml b/crs/Docker/docker-compose.override.yml index 9884f16..4316733 100644 --- a/crs/Docker/docker-compose.override.yml +++ b/crs/Docker/docker-compose.override.yml @@ -76,18 +76,21 @@ services: email.app: environment: - - ASPNETCORE_URLS=http://+:80 - - ASPNETCORE_HTTP_PORTS=5110 - - ASPNETCORE_ENVIRONMENT=Development - # Custom environment variables - - Email__From=${EMAIL_FROM}} - - Email__Host=${EMAIL_HOST} - - Email__Port=${EMAIL_PORT} - - Email__Username=${EMAIL_USERNAME} - - Email__Password=${EMAIL_PASSWORD} - - Retry__Message__Send__Count=3 - - RABBITMQ_DEFAULT_USER=${RABBITMQ_DEFAULT_USER} - - RABBITMQ_DEFAULT_PASS=${RABBITMQ_DEFAULT_PASS} + - ASPNETCORE_URLS=http://+:80 + - ASPNETCORE_HTTP_PORTS=5110 + - ASPNETCORE_ENVIRONMENT=Development + # Custom environment variables + - Email__From=${EMAIL_FROM}} + - Email__Host=${EMAIL_HOST} + - Email__Port=${EMAIL_PORT} + - Email__Username=${EMAIL_USERNAME} + - Email__Password=${EMAIL_PASSWORD} + - Retry__Message__Send__Count=3 + - RABBITMQ_DEFAULT_USER=${RABBITMQ_DEFAULT_USER} + - RABBITMQ_DEFAULT_PASS=${RABBITMQ_DEFAULT_PASS} + - AUTH_ISSUER=${AUTH_ISSUER} + - WEB_AUDIENCE=${WEB_AUDIENCE} + - JWT_SECURITY_KEY=${JWT_SECURITY_KEY} ports: - "5110:80" diff --git a/crs/Services/Catalog/Catalog.App/Configurations/AuthenticationAuthorizationServiceInstaller.cs b/crs/Services/Catalog/Catalog.App/Configurations/AuthenticationAuthorizationServiceInstaller.cs index 858ba11..f244ecb 100644 --- a/crs/Services/Catalog/Catalog.App/Configurations/AuthenticationAuthorizationServiceInstaller.cs +++ b/crs/Services/Catalog/Catalog.App/Configurations/AuthenticationAuthorizationServiceInstaller.cs @@ -1,6 +1,4 @@ -using Microsoft.AspNetCore.Authentication.JwtBearer; - -namespace Catalog.App.Configurations; +namespace Catalog.App.Configurations; internal sealed class AuthenticationAuthorizationServiceInstaller : IServiceInstaller { diff --git a/crs/Services/Catalog/Catalog.App/GlobalUsings.cs b/crs/Services/Catalog/Catalog.App/GlobalUsings.cs index d1f0c96..e44d44e 100644 --- a/crs/Services/Catalog/Catalog.App/GlobalUsings.cs +++ b/crs/Services/Catalog/Catalog.App/GlobalUsings.cs @@ -20,4 +20,5 @@ global using Microsoft.AspNetCore.Diagnostics.HealthChecks; global using OpenTelemetry.Metrics; global using Prometheus; -global using Common.App.HealthChecks; \ No newline at end of file +global using Common.App.HealthChecks; +global using Microsoft.AspNetCore.Authentication.JwtBearer; \ No newline at end of file diff --git a/crs/Services/Email/Email.App/Configurations/AuthenticationAuthorizationServiceInstaller.cs b/crs/Services/Email/Email.App/Configurations/AuthenticationAuthorizationServiceInstaller.cs index 88e8990..1cac009 100644 --- a/crs/Services/Email/Email.App/Configurations/AuthenticationAuthorizationServiceInstaller.cs +++ b/crs/Services/Email/Email.App/Configurations/AuthenticationAuthorizationServiceInstaller.cs @@ -4,6 +4,31 @@ internal sealed class AuthenticationAuthorizationServiceInstaller : IServiceInst { public void Install(IServiceCollection services, IConfiguration configuration) { + services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) + .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, configureOptions => + { + configureOptions.RequireHttpsMetadata = true; + configureOptions.SaveToken = true; + configureOptions.TokenValidationParameters = new TokenValidationParameters + { + ValidateIssuer = true, + ValidIssuer = Env.AUTH_ISSUER, + ValidateAudience = true, + ValidAudiences = [Env.WEB_AUDIENCE], + + RequireExpirationTime = true, + ValidateLifetime = true, + ClockSkew = TimeSpan.Zero, + + RoleClaimType = ClaimTypes.Role, + + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey( + Encoding.UTF8.GetBytes(Env.JWT_SECURITY_KEY)), + }; + }); + + services.AddAuthorization(); } } diff --git a/crs/Services/Email/Email.App/Configurations/GrpcServiceInstaller.cs b/crs/Services/Email/Email.App/Configurations/GrpcServiceInstaller.cs index 1dbe857..d989682 100644 --- a/crs/Services/Email/Email.App/Configurations/GrpcServiceInstaller.cs +++ b/crs/Services/Email/Email.App/Configurations/GrpcServiceInstaller.cs @@ -4,7 +4,7 @@ internal sealed class GrpcServiceInstaller : IServiceInstaller { public void Install(IServiceCollection services, IConfiguration configuration) { - services.AddGrpcClient(options => + services.AddGrpcClient(options => { options.Address = new Uri(Env.IDENTITY_URL); }); diff --git a/crs/Services/Email/Email.App/Email.App.csproj b/crs/Services/Email/Email.App/Email.App.csproj index 09640ab..3ce5b1b 100644 --- a/crs/Services/Email/Email.App/Email.App.csproj +++ b/crs/Services/Email/Email.App/Email.App.csproj @@ -14,6 +14,7 @@ + diff --git a/crs/Services/Email/Email.App/Env.cs b/crs/Services/Email/Email.App/Env.cs index 093443a..00c25ab 100644 --- a/crs/Services/Email/Email.App/Env.cs +++ b/crs/Services/Email/Email.App/Env.cs @@ -8,6 +8,9 @@ internal static class Env public static string IDENTITY_URL => GetEnvironmentVariable("IDENTITY_URL"); public static string RABBITMQ_DEFAULT_USER => GetEnvironmentVariable("RABBITMQ_DEFAULT_USER"); public static string RABBITMQ_DEFAULT_PASS => GetEnvironmentVariable("RABBITMQ_DEFAULT_PASS"); + public static string AUTH_ISSUER => GetEnvironmentVariable("AUTH_ISSUER"); + public static string WEB_AUDIENCE => GetEnvironmentVariable("WEB_AUDIENCE"); + public static string JWT_SECURITY_KEY => GetEnvironmentVariable("JWT_SECURITY_KEY"); public static class ConnectionString { diff --git a/crs/Services/Email/Email.App/GlobalUsings.cs b/crs/Services/Email/Email.App/GlobalUsings.cs index 22f1a83..823bd97 100644 --- a/crs/Services/Email/Email.App/GlobalUsings.cs +++ b/crs/Services/Email/Email.App/GlobalUsings.cs @@ -8,4 +8,8 @@ global using FluentValidation; global using Email.App.OptionsSetup; global using Common.Infrastructure.Middleware; -global using Contracts.Services.Identity; \ No newline at end of file +global using Contracts.Services.Identity; +global using Microsoft.AspNetCore.Authentication.JwtBearer; +global using Microsoft.IdentityModel.Tokens; +global using System.Security.Claims; +global using System.Text; diff --git a/crs/Services/Identity/Idenitty.Grpc/GlobalUsings.cs b/crs/Services/Identity/Idenitty.Grpc/GlobalUsings.cs index 854cfaa..62fac2e 100644 --- a/crs/Services/Identity/Idenitty.Grpc/GlobalUsings.cs +++ b/crs/Services/Identity/Idenitty.Grpc/GlobalUsings.cs @@ -1,3 +1,2 @@ global using Grpc.Core; -global using Contracts.Services.Identity; global using MediatR; \ No newline at end of file diff --git a/crs/Services/Identity/Idenitty.Grpc/Idenitty.Grpc.csproj b/crs/Services/Identity/Idenitty.Grpc/Idenitty.Grpc.csproj index df18c01..8fd29f0 100644 --- a/crs/Services/Identity/Idenitty.Grpc/Idenitty.Grpc.csproj +++ b/crs/Services/Identity/Idenitty.Grpc/Idenitty.Grpc.csproj @@ -15,6 +15,7 @@ + diff --git a/crs/Services/Identity/Idenitty.Grpc/IdentityGrpcService.cs b/crs/Services/Identity/Idenitty.Grpc/IdentityGrpcService.cs deleted file mode 100644 index 809728a..0000000 --- a/crs/Services/Identity/Idenitty.Grpc/IdentityGrpcService.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Idenitty.Grpc; - -public sealed class IdentityGrpcService(ISender sender) : IdentityService.IdentityServiceBase -{ - private readonly ISender _sender = sender; - - public override async Task GetUser(GetUserRequest request, ServerCallContext context) - { - var result = await _sender.Send(); - - return base.GetUser(request, context); - } -} diff --git a/crs/Services/Identity/Idenitty.Grpc/IdentityGrpcServiceV1.cs b/crs/Services/Identity/Idenitty.Grpc/IdentityGrpcServiceV1.cs new file mode 100644 index 0000000..775ff50 --- /dev/null +++ b/crs/Services/Identity/Idenitty.Grpc/IdentityGrpcServiceV1.cs @@ -0,0 +1,24 @@ +using Identity.Application.Users.Queries.GetUserInfoById; +using Identity.V1; + +namespace Idenitty.Grpc; + +public sealed class IdentityGrpcServiceV1(ISender sender) : IdentityService.IdentityServiceBase +{ + private readonly ISender _sender = sender; + + public override async Task GetUserInfo(GetUserRequest request, ServerCallContext context) + { + Guid.TryParse(request.Id, out Guid userId); + + //if(userId == Guid.Empty) + //{ + // context.Status = new Status(StatusCode.InvalidArgument, "Invalid user id"); + //} + + var query = new GetUserInfoByIdQuery(userId); + var result = await _sender.Send(query); + var response = new UserInfo() { s}; + return base.GetUser(request, context); + } +} diff --git a/crs/Services/Identity/Identity.App/Startup.cs b/crs/Services/Identity/Identity.App/Startup.cs index 88775bb..1ae6587 100644 --- a/crs/Services/Identity/Identity.App/Startup.cs +++ b/crs/Services/Identity/Identity.App/Startup.cs @@ -31,7 +31,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { configure.MapControllers(); configure.MapPrometheusScrapingEndpoint(); - configure.MapGrpcService(); + configure.MapGrpcService(); configure.MapHealthChecks("/health", new HealthCheckOptions { ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse diff --git a/crs/Services/Identity/Identity.Application/GlobalUsings.cs b/crs/Services/Identity/Identity.Application/GlobalUsings.cs index 88f94f1..fa9aac6 100644 --- a/crs/Services/Identity/Identity.Application/GlobalUsings.cs +++ b/crs/Services/Identity/Identity.Application/GlobalUsings.cs @@ -15,4 +15,5 @@ global using EventBus.Common.Abstractions; global using Contracts.Services.Identity.Commands; global using Identity.Infrastructure.Hashing; -global using Identity.Infrastructure.Authentication; \ No newline at end of file +global using Identity.Infrastructure.Authentication; +global using Identity.Application.Users.Common; diff --git a/crs/Services/Identity/Identity.Application/Identity.Application.csproj b/crs/Services/Identity/Identity.Application/Identity.Application.csproj index 7ef1778..d7ce476 100644 --- a/crs/Services/Identity/Identity.Application/Identity.Application.csproj +++ b/crs/Services/Identity/Identity.Application/Identity.Application.csproj @@ -17,8 +17,4 @@ - - - - diff --git a/crs/Services/Identity/Identity.Application/Users/Common/UserInfo.cs b/crs/Services/Identity/Identity.Application/Users/Common/UserInfo.cs new file mode 100644 index 0000000..5eeec00 --- /dev/null +++ b/crs/Services/Identity/Identity.Application/Users/Common/UserInfo.cs @@ -0,0 +1,10 @@ +namespace Identity.Application.Users.Common; + +public sealed record UserInfo( + Guid UserId, + string Email, + string FirstName, + string LastName, + bool IsEmailConfirmed, + string Role, + string Gender); diff --git a/crs/Services/Identity/Identity.Application/Users/Queries/GetUserInfoById/GetUserInfoByIdHandler.cs b/crs/Services/Identity/Identity.Application/Users/Queries/GetUserInfoById/GetUserInfoByIdHandler.cs deleted file mode 100644 index 6ea1114..0000000 --- a/crs/Services/Identity/Identity.Application/Users/Queries/GetUserInfoById/GetUserInfoByIdHandler.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Identity.Application.Users.Queries.GetUserInfoById; - -internal sealed class GetUserInfoByIdHandler -{ - -} \ No newline at end of file diff --git a/crs/Services/Identity/Identity.Application/Users/Queries/GetUserInfoById/GetUserInfoByIdQuery.cs b/crs/Services/Identity/Identity.Application/Users/Queries/GetUserInfoById/GetUserInfoByIdQuery.cs new file mode 100644 index 0000000..ea9809f --- /dev/null +++ b/crs/Services/Identity/Identity.Application/Users/Queries/GetUserInfoById/GetUserInfoByIdQuery.cs @@ -0,0 +1,4 @@ +namespace Identity.Application.Users.Queries.GetUserInfoById; + +public sealed record GetUserInfoByIdQuery(Guid Id) : IQuery; + diff --git a/crs/Services/Identity/Identity.Application/Users/Queries/GetUserInfoById/GetUserInfoByIdQueryHandler.cs b/crs/Services/Identity/Identity.Application/Users/Queries/GetUserInfoById/GetUserInfoByIdQueryHandler.cs new file mode 100644 index 0000000..450bcbb --- /dev/null +++ b/crs/Services/Identity/Identity.Application/Users/Queries/GetUserInfoById/GetUserInfoByIdQueryHandler.cs @@ -0,0 +1,26 @@ +namespace Identity.Application.Users.Queries.GetUserInfoById; + +internal sealed class GetUserInfoByIdQueryHandler(IUserRepository userRepository) : IQueryHandler +{ + private readonly IUserRepository _userRepository = userRepository; + + public async Task> Handle(GetUserInfoByIdQuery request, CancellationToken cancellationToken) + { + var userId = new UserId(request.Id); + + var user = await _userRepository.GetUserByIdAsync(userId, cancellationToken); + + if (user is null) + { + return Result.Failure( + UserErrors.UserDoesNotExist); + } + + var userInfo = new UserInfo( + user.Id, + user.Email.Value, + user.(r => r.Name).ToList()); + + return Result.Success(userInfo); + } +} diff --git a/img/Eshop_logo.png b/img/Eshop_logo.png new file mode 100644 index 0000000..b5be050 Binary files /dev/null and b/img/Eshop_logo.png differ