Added authentication and authorization, updated dependency injections, removed hard-coded connection string
This commit is contained in:
		| @@ -14,4 +14,8 @@ | ||||
|       <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.0-preview.7.24405.7" /> | ||||
|     </ItemGroup> | ||||
|  | ||||
|     <ItemGroup> | ||||
|       <Folder Include="DataAccessingServices\" /> | ||||
|     </ItemGroup> | ||||
|  | ||||
| </Project> | ||||
|   | ||||
| @@ -0,0 +1,4 @@ | ||||
| namespace ApplicationLayer.AuthServices.LoginService.Exceptions | ||||
| { | ||||
|     public class IncorrectLoginDataException() : Exception("Incorrect email or password"); | ||||
| } | ||||
| @@ -0,0 +1,12 @@ | ||||
| using ApplicationLayer.AuthServices.Requests; | ||||
|  | ||||
| namespace ApplicationLayer.AuthServices.LoginService | ||||
| { | ||||
|     /// Handles <see cref="UserLoginRequest"/> | ||||
|     public interface ILoginService | ||||
|     { | ||||
|         /// Handle <see cref="UserLoginRequest"/> | ||||
|         /// <returns>JWT-token</returns> | ||||
|         Task<string> LoginAsync(UserLoginRequest request, CancellationToken cancellationToken); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,21 @@ | ||||
| using ApplicationLayer.AuthServices.LoginService.Exceptions; | ||||
| using ApplicationLayer.AuthServices.NeededServices; | ||||
| using ApplicationLayer.AuthServices.Requests; | ||||
|  | ||||
| namespace ApplicationLayer.AuthServices.LoginService | ||||
| { | ||||
|     /// <inheritdoc cref="ILoginService"/> | ||||
|     public class LoginService(IUsersRepository users, ITokenGenerator tokenGenerator) : ILoginService | ||||
|     { | ||||
|         async Task<string> ILoginService.LoginAsync(UserLoginRequest request, CancellationToken cancellationToken) | ||||
|         { | ||||
|             var user = await users.FindByEmailAsync(request.Email, cancellationToken); | ||||
|             if (user is null || user.Password != request.Password) | ||||
|             { | ||||
|                 throw new IncorrectLoginDataException(); | ||||
|             } | ||||
|  | ||||
|             return tokenGenerator.CreateToken(user); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,9 @@ | ||||
| using Domains.Users; | ||||
|  | ||||
| namespace ApplicationLayer.AuthServices.NeededServices | ||||
| { | ||||
|     public interface ITokenGenerator | ||||
|     { | ||||
|         string CreateToken(User user); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,15 @@ | ||||
| using ApplicationLayer.GeneralNeededServices; | ||||
| using Domains.Users; | ||||
|  | ||||
| namespace ApplicationLayer.AuthServices.NeededServices | ||||
| { | ||||
|     /// Repository pattern for <see cref="User"/> | ||||
|     public interface IUsersRepository : IGenericRepository<User> | ||||
|     { | ||||
|         /// Find <see cref="User"/> by email | ||||
|         /// <param name="email"><see cref="User"/>'s email</param> | ||||
|         /// <param name="cancellationToken">Cancellation token</param> | ||||
|         /// <returns>User or null if not found</returns> | ||||
|         Task<User?> FindByEmailAsync(string email, CancellationToken cancellationToken); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,6 @@ | ||||
| using ApplicationLayer.AuthServices.Requests; | ||||
|  | ||||
| namespace ApplicationLayer.AuthServices.RegisterService.Exceptions | ||||
| { | ||||
|     public class UserAlreadyExistsException(RegisterApplicantRequest request) : Exception($"User with email '{request.Email}' already exists"); | ||||
| } | ||||
| @@ -0,0 +1,11 @@ | ||||
| using ApplicationLayer.AuthServices.Requests; | ||||
|  | ||||
| namespace ApplicationLayer.AuthServices.RegisterService | ||||
| { | ||||
|     /// Handles <see cref="RegisterApplicantRequest"/> | ||||
|     public interface IRegisterService | ||||
|     { | ||||
|         /// Handle <see cref="RegisterApplicantRequest"/> | ||||
|         Task Register(RegisterApplicantRequest request, CancellationToken cancellationToken); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,31 @@ | ||||
| using ApplicationLayer.AuthServices.NeededServices; | ||||
| using ApplicationLayer.AuthServices.RegisterService.Exceptions; | ||||
| using ApplicationLayer.AuthServices.Requests; | ||||
| using Domains.Users; | ||||
|  | ||||
| namespace ApplicationLayer.AuthServices.RegisterService | ||||
| { | ||||
|     /// <inheritdoc cref="IRegisterService"/> | ||||
|     public class RegisterService(IUsersRepository users) : IRegisterService | ||||
|     { | ||||
|         async Task IRegisterService.Register(RegisterApplicantRequest request, CancellationToken cancellationToken) | ||||
|         { | ||||
|             if (await users.FindByEmailAsync(request.Email, cancellationToken) is not null) | ||||
|             { | ||||
|                 throw new UserAlreadyExistsException(request); | ||||
|             } | ||||
|  | ||||
|             //TODO mapper | ||||
|             var user = new User | ||||
|             { | ||||
|                 Email = request.Email, | ||||
|                 Password = request.Password, | ||||
|                 Role = Role.Applicant | ||||
|             }; | ||||
|  | ||||
|             await users.AddAsync(user, cancellationToken); | ||||
|             await users.SaveAsync(cancellationToken); | ||||
|             users.GetAllAsync(cancellationToken); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,4 @@ | ||||
| namespace ApplicationLayer.AuthServices.Requests | ||||
| { | ||||
|     public record RegisterApplicantRequest(string Email, string Password); | ||||
| } | ||||
| @@ -0,0 +1,4 @@ | ||||
| namespace ApplicationLayer.AuthServices.Requests | ||||
| { | ||||
|     public record UserLoginRequest(string Email, string Password); | ||||
| } | ||||
| @@ -1,7 +1,7 @@ | ||||
| using ApplicationLayer.GeneralNeededServices; | ||||
| using Domains.ApplicantDomain; | ||||
| 
 | ||||
| namespace ApplicationLayer.Applicants.NeededServices; | ||||
| namespace ApplicationLayer.DataAccessingServices.Applicants.NeededServices; | ||||
| 
 | ||||
| /// Repository pattern for <see cref="Applicant"/> | ||||
| public interface IApplicantsRepository : IGenericRepository<Applicant> { } | ||||
| public interface IApplicantsRepository : IGenericRepository<Applicant>; | ||||
| @@ -0,0 +1,6 @@ | ||||
| using ApplicationLayer.GeneralNeededServices; | ||||
| using Domains.LocationDomain; | ||||
|  | ||||
| namespace ApplicationLayer.DataAccessingServices.Locations.NeededServices; | ||||
|  | ||||
| public interface ICitiesRepository : IGenericRepository<City>; | ||||
| @@ -1,6 +1,6 @@ | ||||
| using ApplicationLayer.GeneralNeededServices; | ||||
| using Domains.LocationDomain; | ||||
| 
 | ||||
| namespace ApplicationLayer.Locations.NeededServices; | ||||
| namespace ApplicationLayer.DataAccessingServices.Locations.NeededServices; | ||||
| 
 | ||||
| public interface ICountriesRepository : IGenericRepository<Country> { } | ||||
| public interface ICountriesRepository : IGenericRepository<Country>; | ||||
| @@ -1,7 +1,7 @@ | ||||
| using ApplicationLayer.VisaApplications.Requests; | ||||
| using ApplicationLayer.DataAccessingServices.VisaApplications.Requests; | ||||
| using Domains.VisaApplicationDomain; | ||||
| 
 | ||||
| namespace ApplicationLayer.VisaApplications.Handlers; | ||||
| namespace ApplicationLayer.DataAccessingServices.VisaApplications.Handlers; | ||||
| 
 | ||||
| public interface IVisaApplicationsRequestHandler | ||||
| { | ||||
| @@ -1,11 +1,11 @@ | ||||
| using ApplicationLayer.Locations.NeededServices; | ||||
| using ApplicationLayer.VisaApplications.Models; | ||||
| using ApplicationLayer.VisaApplications.NeededServices; | ||||
| using ApplicationLayer.VisaApplications.Requests; | ||||
| using ApplicationLayer.DataAccessingServices.Locations.NeededServices; | ||||
| using ApplicationLayer.DataAccessingServices.VisaApplications.Models; | ||||
| using ApplicationLayer.DataAccessingServices.VisaApplications.NeededServices; | ||||
| using ApplicationLayer.DataAccessingServices.VisaApplications.Requests; | ||||
| using Domains.ApplicantDomain; | ||||
| using Domains.VisaApplicationDomain; | ||||
| 
 | ||||
| namespace ApplicationLayer.VisaApplications.Handlers; | ||||
| namespace ApplicationLayer.DataAccessingServices.VisaApplications.Handlers; | ||||
| 
 | ||||
| /// Handles visa requests | ||||
| public class VisaApplicationRequestsHandler( | ||||
| @@ -64,6 +64,7 @@ public class VisaApplicationRequestsHandler( | ||||
|         }; | ||||
| 
 | ||||
|         await applications.AddAsync(visaApplication, cancellationToken); | ||||
|         await applications.SaveAsync(cancellationToken); | ||||
|     } | ||||
| 
 | ||||
|     private async Task<PastVisit> ConvertPastVisitModelToPastVisit(PastVisitModel model, CancellationToken cancellationToken) | ||||
| @@ -1,4 +1,4 @@ | ||||
| namespace ApplicationLayer.VisaApplications.Models; | ||||
| namespace ApplicationLayer.DataAccessingServices.VisaApplications.Models; | ||||
| 
 | ||||
| public class AddressModel | ||||
| { | ||||
| @@ -1,4 +1,4 @@ | ||||
| namespace ApplicationLayer.VisaApplications.Models | ||||
| namespace ApplicationLayer.DataAccessingServices.VisaApplications.Models | ||||
| { | ||||
|     public class PastVisitModel | ||||
|     { | ||||
| @@ -1,4 +1,4 @@ | ||||
| namespace ApplicationLayer.VisaApplications.Models; | ||||
| namespace ApplicationLayer.DataAccessingServices.VisaApplications.Models; | ||||
| 
 | ||||
| public class PlaceOfWorkModel | ||||
| { | ||||
| @@ -1,6 +1,6 @@ | ||||
| using ApplicationLayer.GeneralNeededServices; | ||||
| using Domains.VisaApplicationDomain; | ||||
| 
 | ||||
| namespace ApplicationLayer.VisaApplications.NeededServices; | ||||
| namespace ApplicationLayer.DataAccessingServices.VisaApplications.NeededServices; | ||||
| 
 | ||||
| public interface IVisaApplicationsRepository : IGenericRepository<VisaApplication> { } | ||||
| public interface IVisaApplicationsRepository : IGenericRepository<VisaApplication>; | ||||
| @@ -1,8 +1,8 @@ | ||||
| using ApplicationLayer.VisaApplications.Models; | ||||
| using ApplicationLayer.DataAccessingServices.VisaApplications.Models; | ||||
| using Domains.ApplicantDomain; | ||||
| using Domains.VisaApplicationDomain; | ||||
| 
 | ||||
| namespace ApplicationLayer.VisaApplications.Requests; | ||||
| namespace ApplicationLayer.DataAccessingServices.VisaApplications.Requests; | ||||
| 
 | ||||
| /// Model of visa request from user | ||||
| public record VisaApplicationCreateRequest( | ||||
| @@ -1,4 +1,6 @@ | ||||
| using ApplicationLayer.VisaApplications.Handlers; | ||||
| using ApplicationLayer.AuthServices.LoginService; | ||||
| using ApplicationLayer.AuthServices.RegisterService; | ||||
| using ApplicationLayer.DataAccessingServices.VisaApplications.Handlers; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
|  | ||||
| namespace ApplicationLayer; | ||||
| @@ -11,6 +13,9 @@ public static class DependencyInjection | ||||
|     { | ||||
|         services.AddScoped<IVisaApplicationsRequestHandler, VisaApplicationRequestsHandler>(); | ||||
|  | ||||
|         services.AddScoped<IRegisterService, RegisterService>(); | ||||
|         services.AddScoped<ILoginService, LoginService>(); | ||||
|  | ||||
|         return services; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,8 @@ | ||||
| namespace ApplicationLayer.GeneralNeededServices | ||||
| { | ||||
|     public interface IDateTimeProvider | ||||
|     { | ||||
|         /// Returns current date and time | ||||
|         DateTime Now(); | ||||
|     } | ||||
| } | ||||
| @@ -1,6 +0,0 @@ | ||||
| using ApplicationLayer.GeneralNeededServices; | ||||
| using Domains.LocationDomain; | ||||
|  | ||||
| namespace ApplicationLayer.Locations.NeededServices; | ||||
|  | ||||
| public interface ICitiesRepository : IGenericRepository<City> { } | ||||
							
								
								
									
										13
									
								
								SchengenVisaApi/Domains/Users/Role.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								SchengenVisaApi/Domains/Users/Role.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| namespace Domains.Users | ||||
| { | ||||
|     /// Role of <see cref="User"/> | ||||
|     public enum Role | ||||
|     { | ||||
|         /// Requests visa applications | ||||
|         Applicant, | ||||
|         /// Approves or declines applications | ||||
|         ApprovingAuthority, | ||||
|         /// Manages approving authorities | ||||
|         Admin | ||||
|     } | ||||
| } | ||||
							
								
								
									
										14
									
								
								SchengenVisaApi/Domains/Users/User.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								SchengenVisaApi/Domains/Users/User.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| namespace Domains.Users | ||||
| { | ||||
|     public class User : IEntity | ||||
|     { | ||||
|         /// Unique Identifier of <see cref="User"/> | ||||
|         public Guid Id { get; private set; } = Guid.NewGuid(); | ||||
|  | ||||
|         public Role Role { get; set; } | ||||
|  | ||||
|         public string Email { get; set; } = null!; | ||||
|  | ||||
|         public string Password { get; set; } = null!; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,24 @@ | ||||
| using System.IdentityModel.Tokens.Jwt; | ||||
| using ApplicationLayer.AuthServices.NeededServices; | ||||
| using ApplicationLayer.GeneralNeededServices; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
|  | ||||
| namespace Infrastructure.Auth | ||||
| { | ||||
|     public static class ServiceCollectionsExtensions | ||||
|     { | ||||
|         public static IServiceCollection AddTokenGenerator(this IServiceCollection services, TokenGeneratorOptions options) | ||||
|         { | ||||
|             services.AddSingleton<JwtSecurityTokenHandler>(); | ||||
|             services.AddSingleton<ITokenGenerator, TokenGenerator>(provider => | ||||
|             { | ||||
|                 var tokenHandler = provider.GetRequiredService<JwtSecurityTokenHandler>(); | ||||
|                 var dateTimeProvider = provider.GetRequiredService<IDateTimeProvider>(); | ||||
|  | ||||
|                 return new TokenGenerator(options, tokenHandler, dateTimeProvider); | ||||
|             }); | ||||
|  | ||||
|             return services; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										30
									
								
								SchengenVisaApi/Infrastructure/Auth/TokenGenerator.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								SchengenVisaApi/Infrastructure/Auth/TokenGenerator.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| using System.IdentityModel.Tokens.Jwt; | ||||
| using System.Security.Claims; | ||||
| using ApplicationLayer.AuthServices.NeededServices; | ||||
| using ApplicationLayer.GeneralNeededServices; | ||||
| using Domains.Users; | ||||
|  | ||||
| namespace Infrastructure.Auth | ||||
| { | ||||
|     public class TokenGenerator(TokenGeneratorOptions options, JwtSecurityTokenHandler tokenHandler, IDateTimeProvider dateTimeProvider) | ||||
|         : ITokenGenerator | ||||
|     { | ||||
|         public string CreateToken(User user) | ||||
|         { | ||||
|             var claims = new List<Claim> | ||||
|             { | ||||
|                 new(ClaimTypes.Role, user.Role.ToString()), | ||||
|                 new(ClaimTypes.Email, user.Email) | ||||
|             }; | ||||
|  | ||||
|             var token = new JwtSecurityToken( | ||||
|                 issuer: options.Issuer, | ||||
|                 audience: options.Audience, | ||||
|                 expires: dateTimeProvider.Now().Add(options.ValidTime), | ||||
|                 signingCredentials: options.Credentials, | ||||
|                 claims: claims); | ||||
|  | ||||
|             return tokenHandler.WriteToken(token); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,6 @@ | ||||
| using Microsoft.IdentityModel.Tokens; | ||||
|  | ||||
| namespace Infrastructure.Auth | ||||
| { | ||||
|     public record TokenGeneratorOptions(string Issuer, string Audience, TimeSpan ValidTime, SigningCredentials Credentials); | ||||
| } | ||||
							
								
								
									
										10
									
								
								SchengenVisaApi/Infrastructure/Common/DateTimeProvider.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								SchengenVisaApi/Infrastructure/Common/DateTimeProvider.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| using ApplicationLayer.GeneralNeededServices; | ||||
|  | ||||
| namespace Infrastructure.Common | ||||
| { | ||||
|     /// Implements <see cref="IDateTimeProvider"/> | ||||
|     public class DateTimeProvider : IDateTimeProvider | ||||
|     { | ||||
|         DateTime IDateTimeProvider.Now() => DateTime.Now; | ||||
|     } | ||||
| } | ||||
| @@ -1,4 +1,4 @@ | ||||
| using ApplicationLayer.Applicants.NeededServices; | ||||
| using ApplicationLayer.DataAccessingServices.Applicants.NeededServices; | ||||
| using Domains.ApplicantDomain; | ||||
| using Infrastructure.Database.Generic; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| using ApplicationLayer.Locations.NeededServices; | ||||
| using ApplicationLayer.DataAccessingServices.Locations.NeededServices; | ||||
| using Domains.LocationDomain; | ||||
| using Infrastructure.Database.Generic; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| using ApplicationLayer.Locations.NeededServices; | ||||
| using ApplicationLayer.DataAccessingServices.Locations.NeededServices; | ||||
| using Domains.LocationDomain; | ||||
| using Infrastructure.Database.Generic; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
|   | ||||
| @@ -0,0 +1,22 @@ | ||||
| using Domains.Users; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using Microsoft.EntityFrameworkCore.Metadata.Builders; | ||||
|  | ||||
| namespace Infrastructure.Database.Users.Configuration | ||||
| { | ||||
|     public class UserConfiguration : IEntityTypeConfiguration<User> | ||||
|     { | ||||
|         public void Configure(EntityTypeBuilder<User> entity) | ||||
|         { | ||||
|             entity.Property(u => u.Email) | ||||
|                 .IsUnicode(false) | ||||
|                 .HasMaxLength(254); | ||||
|  | ||||
|             entity.HasIndex(u => u.Email).IsUnique(); | ||||
|  | ||||
|             entity.Property(u => u.Password) | ||||
|                 .IsUnicode(false) | ||||
|                 .HasMaxLength(50); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,17 @@ | ||||
| using ApplicationLayer.AuthServices.NeededServices; | ||||
| using Domains.Users; | ||||
| using Infrastructure.Database.Generic; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
|  | ||||
| namespace Infrastructure.Database.Users.Repositories | ||||
| { | ||||
|     /// <inheritdoc cref="IUsersRepository"/> | ||||
|     public class UsersRepository(IGenericReader reader, IGenericWriter writer, IUnitOfWork unitOfWork) | ||||
|         : GenericRepository<User>(reader, writer, unitOfWork), IUsersRepository | ||||
|     { | ||||
|         async Task<User?> IUsersRepository.FindByEmailAsync(string email, CancellationToken cancellationToken) | ||||
|         { | ||||
|             return await LoadDomain().SingleOrDefaultAsync(u => u.Email == email, cancellationToken); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,4 +1,4 @@ | ||||
| using ApplicationLayer.VisaApplications.NeededServices; | ||||
| using ApplicationLayer.DataAccessingServices.VisaApplications.NeededServices; | ||||
| using Domains.VisaApplicationDomain; | ||||
| using Infrastructure.Database.Generic; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
|   | ||||
| @@ -1,13 +1,19 @@ | ||||
| using ApplicationLayer.Applicants.NeededServices; | ||||
| using ApplicationLayer.Locations.NeededServices; | ||||
| using ApplicationLayer.VisaApplications.NeededServices; | ||||
| using ApplicationLayer.AuthServices.NeededServices; | ||||
| using ApplicationLayer.DataAccessingServices.Applicants.NeededServices; | ||||
| using ApplicationLayer.DataAccessingServices.Locations.NeededServices; | ||||
| using ApplicationLayer.DataAccessingServices.VisaApplications.NeededServices; | ||||
| using ApplicationLayer.GeneralNeededServices; | ||||
| using Infrastructure.Auth; | ||||
| using Infrastructure.Common; | ||||
| using Infrastructure.Database; | ||||
| using Infrastructure.Database.Applicants.Repositories; | ||||
| using Infrastructure.Database.Generic; | ||||
| using Infrastructure.Database.Locations.Repositories.Cities; | ||||
| using Infrastructure.Database.Locations.Repositories.Countries; | ||||
| using Infrastructure.Database.Users.Repositories; | ||||
| using Infrastructure.Database.VisaApplications.Repositories; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using Microsoft.Extensions.Configuration; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| using DbContext = Infrastructure.Database.DbContext; | ||||
|  | ||||
| @@ -17,11 +23,14 @@ namespace Infrastructure; | ||||
| public static class DependencyInjection | ||||
| { | ||||
|     /// Add services needed for Infrastructure layer | ||||
|     public static IServiceCollection AddInfrastructure(this IServiceCollection services) | ||||
|     public static IServiceCollection AddInfrastructure(this IServiceCollection services, | ||||
|         IConfigurationManager configurationManager, | ||||
|         bool isDevelopment) | ||||
|     { | ||||
|         //TODO строка подключения | ||||
|         var databaseName = isDevelopment ? "developmentDB" : "normal'naya database"; | ||||
|  | ||||
|         services.AddDbContextFactory<DbContext>(opts => | ||||
|             opts.UseSqlServer("Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=visadb;Integrated Security=True;")); | ||||
|             opts.UseSqlServer(configurationManager.GetConnectionString(databaseName))); | ||||
|  | ||||
|         services.AddScoped<IGenericReader>(serviceProvider => serviceProvider.GetRequiredService<DbContext>()); | ||||
|         services.AddScoped<IGenericWriter>(serviceProvider => serviceProvider.GetRequiredService<DbContext>()); | ||||
| @@ -31,6 +40,9 @@ public static class DependencyInjection | ||||
|         services.AddScoped<IVisaApplicationsRepository, VisaApplicationsRepository>(); | ||||
|         services.AddScoped<ICitiesRepository, CitiesRepository>(); | ||||
|         services.AddScoped<ICountriesRepository, CountriesRepository>(); | ||||
|         services.AddScoped<IUsersRepository, UsersRepository>(); | ||||
|  | ||||
|         services.AddSingleton<IDateTimeProvider, DateTimeProvider>(); | ||||
|  | ||||
|         return services; | ||||
|     } | ||||
|   | ||||
| @@ -11,6 +11,7 @@ | ||||
|     </ItemGroup> | ||||
|  | ||||
|     <ItemGroup> | ||||
|       <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.8" /> | ||||
|       <PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0-preview.7.24405.3" /> | ||||
|       <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.0-preview.7.24405.3" /> | ||||
|       <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0-preview.7.24405.3" /> | ||||
|   | ||||
| @@ -0,0 +1,27 @@ | ||||
| using ApplicationLayer.AuthServices.LoginService; | ||||
| using ApplicationLayer.AuthServices.RegisterService; | ||||
| using ApplicationLayer.AuthServices.Requests; | ||||
| using Microsoft.AspNetCore.Identity.Data; | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
|  | ||||
| namespace SchengenVisaApi.Controllers | ||||
| { | ||||
|     [ApiController] | ||||
|     [Route("auth")] | ||||
|     public class UsersController(IRegisterService registerService, ILoginService loginService) : Controller | ||||
|     { | ||||
|         [HttpPost] | ||||
|         public async Task<IActionResult> Register(RegisterApplicantRequest request, CancellationToken cancellationToken) | ||||
|         { | ||||
|             await registerService.Register(request, cancellationToken); | ||||
|             return Created(); | ||||
|         } | ||||
|  | ||||
|         [HttpGet] | ||||
|         public async Task<IActionResult> Login(string email, string password, CancellationToken cancellationToken) | ||||
|         { | ||||
|             var result = await loginService.LoginAsync(new UserLoginRequest(email, password), cancellationToken); | ||||
|             return Ok(result); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,5 +1,5 @@ | ||||
| using ApplicationLayer.VisaApplications.Handlers; | ||||
| using ApplicationLayer.VisaApplications.Requests; | ||||
| using ApplicationLayer.DataAccessingServices.VisaApplications.Handlers; | ||||
| using ApplicationLayer.DataAccessingServices.VisaApplications.Requests; | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
|  | ||||
| namespace SchengenVisaApi.Controllers; | ||||
|   | ||||
| @@ -1,6 +1,10 @@ | ||||
| using System.Reflection; | ||||
| using System.Text; | ||||
| using ApplicationLayer; | ||||
| using Infrastructure; | ||||
| using Infrastructure.Auth; | ||||
| using Microsoft.AspNetCore.Authentication.JwtBearer; | ||||
| using Microsoft.IdentityModel.Tokens; | ||||
|  | ||||
| namespace SchengenVisaApi; | ||||
|  | ||||
| @@ -8,21 +12,61 @@ namespace SchengenVisaApi; | ||||
| public static class DependencyInjection | ||||
| { | ||||
|     /// Add needed services | ||||
|     public static IServiceCollection RegisterServices(this IServiceCollection services) | ||||
|     public static void RegisterServices(this WebApplicationBuilder builder) | ||||
|     { | ||||
|         services | ||||
|             .AddInfrastructure() | ||||
|         var config = builder.Configuration; | ||||
|         var environment = builder.Environment; | ||||
|  | ||||
|         builder.Services | ||||
|             .AddInfrastructure(config, environment.IsDevelopment()) | ||||
|             .AddApplicationLayer() | ||||
|             .AddPresentation(); | ||||
|             .AddAuth(config) | ||||
|             .AddPresentation(environment); | ||||
|     } | ||||
|  | ||||
|     /// Add services needed for Presentation layer | ||||
|     private static void AddPresentation(this IServiceCollection services, | ||||
|         IWebHostEnvironment environment) | ||||
|     { | ||||
|         if (environment.IsDevelopment()) | ||||
|         { | ||||
|             services.AddSwagger(); | ||||
|         } | ||||
|  | ||||
|         services.AddControllers(); | ||||
|     } | ||||
|  | ||||
|     /// Adds authentication, authorization and token generator | ||||
|     private static IServiceCollection AddAuth(this IServiceCollection services, IConfigurationManager configurationManager) | ||||
|     { | ||||
|         var parameters = new TokenValidationParameters | ||||
|         { | ||||
|             ValidIssuer = configurationManager["JwtSettings:Issuer"], | ||||
|             ValidAudience = configurationManager["JwtSettings:Audience"], | ||||
|             IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configurationManager["JwtSettings:Key"]!)), | ||||
|             ValidateIssuer = true, | ||||
|             ValidateAudience = true, | ||||
|             ValidateLifetime = true, | ||||
|             ValidateIssuerSigningKey = true | ||||
|         }; | ||||
|  | ||||
|         services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) | ||||
|             .AddJwtBearer(opts => opts.TokenValidationParameters = parameters); | ||||
|         services.AddAuthorization(); | ||||
|  | ||||
|         services.AddTokenGenerator(new TokenGeneratorOptions( | ||||
|             Issuer: parameters.ValidIssuer!, | ||||
|             Audience: parameters.ValidAudience!, | ||||
|             Credentials: new SigningCredentials(parameters.IssuerSigningKey, SecurityAlgorithms.HmacSha256), | ||||
|             ValidTime: TimeSpan.FromMinutes(30) | ||||
|         )); | ||||
|  | ||||
|         return services; | ||||
|     } | ||||
|  | ||||
|     /// Add services needed for Presentation layer | ||||
|     private static void AddPresentation(this IServiceCollection services) | ||||
|     /// Add swagger | ||||
|     private static void AddSwagger(this IServiceCollection services) | ||||
|     { | ||||
|         services.AddControllers(); | ||||
|         services.AddEndpointsApiExplorer(); | ||||
|         services.AddSwaggerGen(options => | ||||
|         { | ||||
|             var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; | ||||
|   | ||||
| @@ -1,11 +1,12 @@ | ||||
| namespace SchengenVisaApi; | ||||
|  | ||||
| #pragma warning disable CS1591 | ||||
| public class Program | ||||
| { | ||||
|     public static void Main(string[] args) | ||||
|     { | ||||
|         var builder = WebApplication.CreateBuilder(args); | ||||
|         builder.Services.RegisterServices(); | ||||
|         builder.RegisterServices(); | ||||
|  | ||||
|         var app = builder.Build(); | ||||
|         app.ConfigurePipelineRequest(); | ||||
|   | ||||
| @@ -11,6 +11,9 @@ public static class PipelineRequest | ||||
|  | ||||
|         app.UseHttpsRedirection(); | ||||
|  | ||||
|         app.UseAuthentication() | ||||
|             .UseAuthorization(); | ||||
|  | ||||
|         app.MapControllers(); | ||||
|  | ||||
|         return app; | ||||
|   | ||||
| @@ -5,5 +5,16 @@ | ||||
|       "Microsoft.AspNetCore": "Warning" | ||||
|     } | ||||
|   }, | ||||
|   "AllowedHosts": "*" | ||||
|   "AllowedHosts": "*", | ||||
|  | ||||
|   "ConnectionStrings": { | ||||
|     "developmentDB": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=visadb;Integrated Security=True;", | ||||
|     "normal'naya db": "" | ||||
|   }, | ||||
|  | ||||
|   "JwtSettings": { | ||||
|     "Issuer":"visaAPI", | ||||
|     "Audience":"visaClient", | ||||
|     "Key": "frsjiajfapojrpwauflakpiowaidoaplakrf" | ||||
|   } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user