From 6fd9472f2bd5f6aa5bfee6cd32e88c652de68493 Mon Sep 17 00:00:00 2001 From: MeysamMoghaddam <65253484+MeysamMoghaddam@users.noreply.github.com> Date: Sat, 27 Sep 2025 23:59:05 +0330 Subject: [PATCH] Generator Changes at 9/27/2025 11:50:52 PM --- .../Common/Interfaces/IGenerateJwtToken.cs | 5 ++ .../Queries/GetJwtToken/GetJwtTokenQuery.cs | 7 ++ .../GetJwtToken/GetJwtTokenQueryHandler.cs | 22 ++++++ .../GetJwtToken/GetJwtTokenQueryValidator.cs | 16 +++++ .../GetJwtToken/GetJwtTokenResponseDto.cs | 7 ++ .../ConfigureServices.cs | 2 + .../Services/GenerateJwtTokenService.cs | 67 +++++++++++++++++++ .../CMSMicroservice.Protobuf.csproj | 2 +- .../Protos/user.proto | 14 ++++ .../User/GetJwtTokenRequestValidator.cs | 19 ++++++ .../Services/UserService.cs | 5 ++ 11 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 src/CMSMicroservice.Application/Common/Interfaces/IGenerateJwtToken.cs create mode 100644 src/CMSMicroservice.Application/UserCQ/Queries/GetJwtToken/GetJwtTokenQuery.cs create mode 100644 src/CMSMicroservice.Application/UserCQ/Queries/GetJwtToken/GetJwtTokenQueryHandler.cs create mode 100644 src/CMSMicroservice.Application/UserCQ/Queries/GetJwtToken/GetJwtTokenQueryValidator.cs create mode 100644 src/CMSMicroservice.Application/UserCQ/Queries/GetJwtToken/GetJwtTokenResponseDto.cs create mode 100644 src/CMSMicroservice.Infrastructure/Services/GenerateJwtTokenService.cs create mode 100644 src/CMSMicroservice.Protobuf/Validator/User/GetJwtTokenRequestValidator.cs diff --git a/src/CMSMicroservice.Application/Common/Interfaces/IGenerateJwtToken.cs b/src/CMSMicroservice.Application/Common/Interfaces/IGenerateJwtToken.cs new file mode 100644 index 0000000..1b08985 --- /dev/null +++ b/src/CMSMicroservice.Application/Common/Interfaces/IGenerateJwtToken.cs @@ -0,0 +1,5 @@ +namespace CMSMicroservice.Application.Common.Interfaces; +public interface IGenerateJwtToken +{ + Task GenerateJwtToken(User user); +} diff --git a/src/CMSMicroservice.Application/UserCQ/Queries/GetJwtToken/GetJwtTokenQuery.cs b/src/CMSMicroservice.Application/UserCQ/Queries/GetJwtToken/GetJwtTokenQuery.cs new file mode 100644 index 0000000..aa8458a --- /dev/null +++ b/src/CMSMicroservice.Application/UserCQ/Queries/GetJwtToken/GetJwtTokenQuery.cs @@ -0,0 +1,7 @@ +namespace CMSMicroservice.Application.UserCQ.Queries.GetJwtToken; +public record GetJwtTokenQuery : IRequest +{ + //شناسه + public long Id { get; init; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/UserCQ/Queries/GetJwtToken/GetJwtTokenQueryHandler.cs b/src/CMSMicroservice.Application/UserCQ/Queries/GetJwtToken/GetJwtTokenQueryHandler.cs new file mode 100644 index 0000000..dd97e5c --- /dev/null +++ b/src/CMSMicroservice.Application/UserCQ/Queries/GetJwtToken/GetJwtTokenQueryHandler.cs @@ -0,0 +1,22 @@ +namespace CMSMicroservice.Application.UserCQ.Queries.GetJwtToken; +public class GetJwtTokenQueryHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + private readonly IGenerateJwtToken _generateJwt; + + public GetJwtTokenQueryHandler(IApplicationDbContext context, IGenerateJwtToken generateJwt) + { + _context = context; + _generateJwt = generateJwt; + } + + public async Task Handle(GetJwtTokenQuery request, CancellationToken cancellationToken) + { + var user = await _context.Users + .FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken) ?? throw new NotFoundException(nameof(User), request.Id); + return new GetJwtTokenResponseDto() + { + Token = await _generateJwt.GenerateJwtToken(user), + }; + } +} diff --git a/src/CMSMicroservice.Application/UserCQ/Queries/GetJwtToken/GetJwtTokenQueryValidator.cs b/src/CMSMicroservice.Application/UserCQ/Queries/GetJwtToken/GetJwtTokenQueryValidator.cs new file mode 100644 index 0000000..4a37185 --- /dev/null +++ b/src/CMSMicroservice.Application/UserCQ/Queries/GetJwtToken/GetJwtTokenQueryValidator.cs @@ -0,0 +1,16 @@ +namespace CMSMicroservice.Application.UserCQ.Queries.GetJwtToken; +public class GetJwtTokenQueryValidator : AbstractValidator +{ + public GetJwtTokenQueryValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetJwtTokenQuery)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/UserCQ/Queries/GetJwtToken/GetJwtTokenResponseDto.cs b/src/CMSMicroservice.Application/UserCQ/Queries/GetJwtToken/GetJwtTokenResponseDto.cs new file mode 100644 index 0000000..af3d7bc --- /dev/null +++ b/src/CMSMicroservice.Application/UserCQ/Queries/GetJwtToken/GetJwtTokenResponseDto.cs @@ -0,0 +1,7 @@ +namespace CMSMicroservice.Application.UserCQ.Queries.GetJwtToken; +public class GetJwtTokenResponseDto +{ + //توکن + public string Token { get; set; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Infrastructure/ConfigureServices.cs b/src/CMSMicroservice.Infrastructure/ConfigureServices.cs index 026fa83..8c627a8 100644 --- a/src/CMSMicroservice.Infrastructure/ConfigureServices.cs +++ b/src/CMSMicroservice.Infrastructure/ConfigureServices.cs @@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Http; using System.Diagnostics; using Microsoft.IdentityModel.Tokens; using System.Text; +using CMSMicroservice.Infrastructure.Services; namespace Microsoft.Extensions.DependencyInjection; @@ -17,6 +18,7 @@ public static class ConfigureServices { services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddScoped(p => p.GetRequiredService()); if (configuration.GetValue("UseInMemoryDatabase")) { diff --git a/src/CMSMicroservice.Infrastructure/Services/GenerateJwtTokenService.cs b/src/CMSMicroservice.Infrastructure/Services/GenerateJwtTokenService.cs new file mode 100644 index 0000000..381e15e --- /dev/null +++ b/src/CMSMicroservice.Infrastructure/Services/GenerateJwtTokenService.cs @@ -0,0 +1,67 @@ +using CMSMicroservice.Application.Common.Interfaces; +using CMSMicroservice.Domain.Entities; +using Microsoft.Extensions.Configuration; +using Microsoft.IdentityModel.Tokens; +using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Text; + +namespace CMSMicroservice.Infrastructure.Services; +public class GenerateJwtTokenService : IGenerateJwtToken +{ + private readonly IConfiguration _configuration; + + public GenerateJwtTokenService(IConfiguration configuration) + { + _configuration = configuration; + } + + public async Task GenerateJwtToken(User user) + { + var lastModified = user.LastModified ?? user.Created; + var claims = new List + { + new(ClaimTypes.NameIdentifier, user.Id.ToString()), + new(ClaimTypes.MobilePhone, user.Mobile), + new("ReferralCode", user.ReferralCode), + new(ClaimTypes.Name, $"{user.FirstName} {user.LastName}") + }; + + if (!string.IsNullOrWhiteSpace(user.FirstName)) + claims.Add(new Claim("FirstName", user.FirstName)); + + if (!string.IsNullOrWhiteSpace(user.LastName)) + claims.Add(new Claim("LastName", user.LastName)); + + + if (user.UserRoles != null && user.UserRoles.Any()) + { + foreach (var userRole in user.UserRoles) + { + claims.Add(new Claim(ClaimTypes.Role, userRole.Role.Name)); + } + if (user.UserRoles.Max(x => x.Created) > lastModified) + lastModified = user.UserRoles.Max(x => x.Created); + if (user.UserRoles.Where(x => x.LastModified != null).Max(x => x.LastModified) > lastModified) + lastModified = user.UserRoles.Where(x => x.LastModified != null).Max(x => x.Created); + } + + claims.Add(new Claim("LastModified", lastModified.ToString())); + + var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JwtSecurityKey"])); + var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); + var expiry = DateTime.Now.AddDays(Convert.ToInt32(_configuration["JwtExpiryInDays"])); + + var token = new JwtSecurityToken( + _configuration["JwtIssuer"], + _configuration["JwtAudience"], + claims, + expires: expiry, + signingCredentials: creds + ); + var _token = new JwtSecurityTokenHandler().WriteToken(token); + return _token; + } + +} diff --git a/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj b/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj index 97553fd..b721580 100644 --- a/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj +++ b/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj @@ -4,7 +4,7 @@ net7.0 enable enable - 0.0.112 + 0.0.113 None False False diff --git a/src/CMSMicroservice.Protobuf/Protos/user.proto b/src/CMSMicroservice.Protobuf/Protos/user.proto index 6deaa50..e528a9a 100644 --- a/src/CMSMicroservice.Protobuf/Protos/user.proto +++ b/src/CMSMicroservice.Protobuf/Protos/user.proto @@ -43,6 +43,12 @@ service UserContract }; }; + rpc GetJwtToken(GetJwtTokenRequest) returns (GetJwtTokenResponse){ + option (google.api.http) = { + get: "/GetJwtToken" + + }; + }; } message CreateNewUserRequest { @@ -123,3 +129,11 @@ message GetAllUserByFilterResponseModel bool is_mobile_verified = 9; google.protobuf.Timestamp mobile_verified_at = 10; } +message GetJwtTokenRequest +{ + int64 id = 1; +} +message GetJwtTokenResponse +{ + string token = 1; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/User/GetJwtTokenRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/User/GetJwtTokenRequestValidator.cs new file mode 100644 index 0000000..ed3e385 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/User/GetJwtTokenRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.User; +namespace CMSMicroservice.Protobuf.Validator.User; + +public class GetJwtTokenRequestValidator : AbstractValidator +{ + public GetJwtTokenRequestValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetJwtTokenRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.WebApi/Services/UserService.cs b/src/CMSMicroservice.WebApi/Services/UserService.cs index f01ed16..e0a1fb0 100644 --- a/src/CMSMicroservice.WebApi/Services/UserService.cs +++ b/src/CMSMicroservice.WebApi/Services/UserService.cs @@ -5,6 +5,7 @@ using CMSMicroservice.Application.UserCQ.Commands.UpdateUser; using CMSMicroservice.Application.UserCQ.Commands.DeleteUser; using CMSMicroservice.Application.UserCQ.Queries.GetUser; using CMSMicroservice.Application.UserCQ.Queries.GetAllUserByFilter; +using CMSMicroservice.Application.UserCQ.Queries.GetJwtToken; namespace CMSMicroservice.WebApi.Services; public class UserService : UserContract.UserContractBase { @@ -34,4 +35,8 @@ public class UserService : UserContract.UserContractBase { return await _dispatchRequestToCQRS.Handle(request, context); } + public override async Task GetJwtToken(GetJwtTokenRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } }