From bc64ae371a5f5ec97b7e369d0a996c676b513716 Mon Sep 17 00:00:00 2001 From: PC_KYJ Date: Wed, 24 Jan 2024 01:10:24 +0900 Subject: [PATCH 1/5] =?UTF-8?q?Feat:=20=EC=84=9C=EB=B9=84=EC=8A=A4?= =?UTF-8?q?=EB=A0=88=EC=9D=B4=EC=96=B4=EC=97=90=20Logger=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80,=20=ED=86=A0=ED=81=B0=20=EC=9E=91=EC=97=85=20?= =?UTF-8?q?=EC=A4=91=EA=B0=84=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/CommentController.cs | 3 +- EveryPinApi/Program.cs | 99 ++++++++++--------- .../Models/IAuthenticationService.cs | 2 + Service/Models/AuthenticationService.cs | 92 +++++++++++++++-- Service/Models/CommentService.cs | 4 +- Service/Models/LikeService.cs | 5 +- Service/Models/PostPhotoService.cs | 5 +- Service/Models/PostService.cs | 5 +- Service/Models/ProfileService.cs | 5 +- Service/Service.csproj | 3 +- Service/ServiceManager.cs | 15 +-- Shared/Shared.csproj | 4 + 12 files changed, 170 insertions(+), 72 deletions(-) diff --git a/EveryPinApi.Presentation/Controllers/CommentController.cs b/EveryPinApi.Presentation/Controllers/CommentController.cs index e5a9f7c..8289f9a 100644 --- a/EveryPinApi.Presentation/Controllers/CommentController.cs +++ b/EveryPinApi.Presentation/Controllers/CommentController.cs @@ -8,6 +8,7 @@ using System.Text; using System.Threading.Tasks; using Microsoft.Extensions.Logging; +using Microsoft.AspNetCore.Authorization; namespace EveryPinApi.Presentation.Controllers { @@ -24,7 +25,7 @@ public CommentController(ILogger logger, IServiceManager serv _service = service; } - [HttpGet] + [HttpGet(Name = "GetComment")] public IActionResult GetAllComment() { var companies = _service.CommentService.GetAllComment(trackChanges: false); diff --git a/EveryPinApi/Program.cs b/EveryPinApi/Program.cs index 4cc59b2..f014fe3 100644 --- a/EveryPinApi/Program.cs +++ b/EveryPinApi/Program.cs @@ -3,65 +3,66 @@ using Microsoft.AspNetCore.HttpOverrides; using Microsoft.Extensions.Logging; - var builder = WebApplication.CreateBuilder(args); +{ + // Add services to the container. + builder.Services.ConfigureCors(); // CORS + builder.Services.ConfigureRepositoryManager(); // RepositoryManager ߰ + builder.Services.ConfigureServiceManager(); // ServiceManager ߰ + builder.Services.ConfigureSqlContext(builder.Configuration); + + // Presentation Layer ControllerBase ϵ + builder.Services.AddControllers() + .AddApplicationPart(typeof(EveryPinApi.Presentation.AssemblyReference).Assembly); + + // Swagger/OpenAPI + builder.Services.AddEndpointsApiExplorer(); + builder.Services.AddSwaggerGen(); + + // Azure Logging + builder.Logging.AddAzureWebAppDiagnostics(); + builder.Services.ConfigureLoggerFile(); + builder.Services.ConfigureLoggerBlob(); + + // Auth + builder.Services.AddAuthentication(); + builder.Services.ConfigureIdentity(); + builder.Services.ConfigureJWT(builder.Configuration); + + // AutoMapper + builder.Services.AddAutoMapper(typeof(Program)); +} - - -// Add services to the container. -builder.Services.ConfigureCors(); // CORS -builder.Services.ConfigureRepositoryManager(); // RepositoryManager ߰ -builder.Services.ConfigureServiceManager(); // ServiceManager ߰ -builder.Services.ConfigureSqlContext(builder.Configuration); - -// Presentation Layer ControllerBase ϵ -builder.Services.AddControllers() - .AddApplicationPart(typeof(EveryPinApi.Presentation.AssemblyReference).Assembly); - -// Swagger/OpenAPI -builder.Services.AddEndpointsApiExplorer(); -builder.Services.AddSwaggerGen(); - -// Azure Logging -builder.Logging.AddAzureWebAppDiagnostics(); -builder.Services.ConfigureLoggerFile(); -builder.Services.ConfigureLoggerBlob(); - -// Auth -builder.Services.AddAuthentication(); -builder.Services.ConfigureIdentity(); -builder.Services.ConfigureJWT(builder.Configuration); - -// AutoMapper -builder.Services.AddAutoMapper(typeof(Program)); var app = builder.Build(); +{ + app.ConfigureExceptionHandler(app.Logger); -app.ConfigureExceptionHandler(app.Logger); + // Configure the HTTP request pipeline. + //if (app.Environment.IsDevelopment()) + //{ + // app.UseDeveloperExceptionPage(); + //} -// Configure the HTTP request pipeline. -//if (app.Environment.IsDevelopment()) -//{ -// app.UseDeveloperExceptionPage(); -//} + // Swagger + app.UseSwagger(); + app.UseSwaggerUI(); -// Swagger -app.UseSwagger(); -app.UseSwaggerUI(); + app.UseStaticFiles(); + app.UseForwardedHeaders(new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.All + }); -app.UseStaticFiles(); -app.UseForwardedHeaders(new ForwardedHeadersOptions -{ - ForwardedHeaders = ForwardedHeaders.All -}); + //app.UseDeveloperExceptionPage(); // 뵵. Ȱȭ , ۷ι α X -//app.UseDeveloperExceptionPage(); // 뵵. Ȱȭ , ۷ι α X + // auth + app.UseAuthentication(); + app.UseAuthorization(); -// auth -app.UseAuthentication(); -app.UseAuthorization(); + app.UseCors("CorsPolicy"); -app.UseCors("CorsPolicy"); + app.MapControllers(); +} -app.MapControllers(); app.Run(); diff --git a/Service.Contracts/Models/IAuthenticationService.cs b/Service.Contracts/Models/IAuthenticationService.cs index 96b6551..3c30b1d 100644 --- a/Service.Contracts/Models/IAuthenticationService.cs +++ b/Service.Contracts/Models/IAuthenticationService.cs @@ -11,6 +11,8 @@ namespace Service.Contracts.Models public interface IAuthenticationService { Task RegisterUser(RegistUserDto registUserDto); + Task ValidateUser(); + Task CreateToken(); } } diff --git a/Service/Models/AuthenticationService.cs b/Service/Models/AuthenticationService.cs index 9863a86..73a711d 100644 --- a/Service/Models/AuthenticationService.cs +++ b/Service/Models/AuthenticationService.cs @@ -7,35 +7,109 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Security.Claims; using System.Text; using System.Threading.Tasks; +using System.IdentityModel.Tokens.Jwt; +using Microsoft.IdentityModel.Tokens; +using Microsoft.Extensions.Logging; namespace Service.Models { internal sealed class AuthenticationService : IAuthenticationService { - //private readonly ILoggerManager _logger; + private readonly ILogger _logger; private readonly IMapper _mapper; private readonly UserManager _userManager; private readonly IConfiguration _configuration; - public AuthenticationService(IMapper mapper, + public AuthenticationService(ILogger logger, IMapper mapper, UserManager userManager, IConfiguration configuration) { - //_logger = logger; + _logger = logger; _mapper = mapper; _userManager = userManager; _configuration = configuration; } - public async Task RegisterUser(RegistUserDto registUserDto) + public Task CreateToken() { - var user = _mapper.Map(registUserDto); - var result = await _userManager.CreateAsync(user, registUserDto.Password); - if (result.Succeeded) - await _userManager.AddToRolesAsync(user, registUserDto.Roles); - return result; + throw new NotImplementedException(); } + + public Task RegisterUser(RegistUserDto registUserDto) + { + throw new NotImplementedException(); + } + + public Task ValidateUser() + { + throw new NotImplementedException(); + } + + //public async Task RegisterUser(RegistUserDto registUserDto) + //{ + // var user = _mapper.Map(registUserDto); + // var result = await _userManager.CreateAsync(user, registUserDto.Password); + // if (result.Succeeded) + // await _userManager.AddToRolesAsync(user, registUserDto.Roles); + // return result; + //} + // + //public async Task ValidateUser(UserForAuthenticationDto userForAuth) + //{ + // _user = await _userManager.FindByNameAsync(userForAuth.UserName); + // var result = (_user != null && await _userManager.CheckPasswordAsync(_user, userForAuth.Password)); + // + // if (!result) + // _logger.LogWarning($"{nameof(ValidateUser)}: 인증 실패. 잘못된 사용자 이름 또는 비밀번호."); + // + // return result; + //} + // + //public async Task CreateToken() + //{ + // var signingCredentials = GetSigningCredentials(); + // var claims = await GetClaims(); + // var tokenOptions = GenerateTokenOptions(signingCredentials, claims); + // return new JwtSecurityTokenHandler().WriteToken(tokenOptions); + //} + // + //private SigningCredentials GetSigningCredentials() + //{ + // var key = Encoding.UTF8.GetBytes(Environment.GetEnvironmentVariable("SECRET")); + // var secret = new SymmetricSecurityKey(key); + // return new SigningCredentials(secret, SecurityAlgorithms.HmacSha256); + //} + // + //private async Task> GetClaims() + //{ + // var claims = new List + // { + // new Claim(ClaimTypes.Name, _user.UserName) + // }; + // + // var roles = await _userManager.GetRolesAsync(_user); + // foreach (var role in roles) + // { + // claims.Add(new Claim(ClaimTypes.Role, role)); + // } + // return claims; + //} + // + //private JwtSecurityToken GenerateTokenOptions(SigningCredentials signingCredentials, List claims) + //{ + // var jwtSettings = _configuration.GetSection("JwtSettings"); + // var tokenOptions = new JwtSecurityToken + // ( + // issuer: jwtSettings["validIssuer"], + // audience: jwtSettings["validAudience"], + // claims: claims, + // expires: DateTime.Now.AddMinutes(Convert.ToDouble(jwtSettings["expires"])), + // signingCredentials: signingCredentials + // ); + // return tokenOptions; + //} } } diff --git a/Service/Models/CommentService.cs b/Service/Models/CommentService.cs index 1c643c9..ade5298 100644 --- a/Service/Models/CommentService.cs +++ b/Service/Models/CommentService.cs @@ -14,11 +14,13 @@ namespace Service.Models { internal sealed class CommentService : ICommentService { + private readonly ILogger _logger; private readonly IRepositoryManager _repository; private readonly IMapper _mapper; - public CommentService(IRepositoryManager repository, IMapper mapper) + public CommentService(ILogger logger, IRepositoryManager repository, IMapper mapper) { + _logger = logger; _repository = repository; _mapper = mapper; } diff --git a/Service/Models/LikeService.cs b/Service/Models/LikeService.cs index ba5a3c9..84d4685 100644 --- a/Service/Models/LikeService.cs +++ b/Service/Models/LikeService.cs @@ -2,6 +2,7 @@ using Contracts.Repository; using Entites.Models; using Microsoft.Extensions.Logging; +using Service.Models; using Shared.DataTransferObject; using System; using System.Collections.Generic; @@ -14,11 +15,13 @@ namespace Service.Contracts.Models { internal sealed class LikeService : ILikeService { + private readonly ILogger _logger; private readonly IRepositoryManager _repository; private readonly IMapper _mapper; - public LikeService(IRepositoryManager repository, IMapper mapper) + public LikeService(ILogger logger, IRepositoryManager repository, IMapper mapper) { + _logger = logger; _repository = repository; _mapper = mapper; } diff --git a/Service/Models/PostPhotoService.cs b/Service/Models/PostPhotoService.cs index 42a5daf..3c32241 100644 --- a/Service/Models/PostPhotoService.cs +++ b/Service/Models/PostPhotoService.cs @@ -2,6 +2,7 @@ using Contracts.Repository; using Entites.Models; using Microsoft.Extensions.Logging; +using Service.Models; using Shared.DataTransferObject; using System; using System.Collections.Generic; @@ -14,11 +15,13 @@ namespace Service.Contracts.Models { internal sealed class PostPhotoService : IPostPhotoService { + private readonly ILogger _logger; private readonly IRepositoryManager _repository; private readonly IMapper _mapper; - public PostPhotoService(IRepositoryManager repository, IMapper mapper) + public PostPhotoService(ILogger logger, IRepositoryManager repository, IMapper mapper) { + _logger = logger; _repository = repository; _mapper = mapper; } diff --git a/Service/Models/PostService.cs b/Service/Models/PostService.cs index 200f867..7d40a39 100644 --- a/Service/Models/PostService.cs +++ b/Service/Models/PostService.cs @@ -2,6 +2,7 @@ using Contracts.Repository; using Entites.Models; using Microsoft.Extensions.Logging; +using Service.Models; using Shared.DataTransferObject; using System; using System.Collections.Generic; @@ -14,11 +15,13 @@ namespace Service.Contracts.Models { internal sealed class PostService : IPostService { + private readonly ILogger _logger; private readonly IRepositoryManager _repository; private readonly IMapper _mapper; - public PostService(IRepositoryManager repository, IMapper mapper) + public PostService(ILogger logger, IRepositoryManager repository, IMapper mapper) { + _logger = logger; _repository = repository; _mapper = mapper; } diff --git a/Service/Models/ProfileService.cs b/Service/Models/ProfileService.cs index a1fcc21..a775601 100644 --- a/Service/Models/ProfileService.cs +++ b/Service/Models/ProfileService.cs @@ -2,6 +2,7 @@ using Contracts.Repository; using Entites.Models; using Microsoft.Extensions.Logging; +using Service.Models; using Shared.DataTransferObject; using System; using System.Collections.Generic; @@ -14,11 +15,13 @@ namespace Service.Contracts.Models { internal sealed class ProfileService : IProfileService { + private readonly ILogger _logger; private readonly IRepositoryManager _repository; private readonly IMapper _mapper; - public ProfileService(IRepositoryManager repository, IMapper mapper) + public ProfileService(ILogger logger, IRepositoryManager repository, IMapper mapper) { + _logger = logger; _repository = repository; _mapper = mapper; } diff --git a/Service/Service.csproj b/Service/Service.csproj index 1bae81d..c25b22d 100644 --- a/Service/Service.csproj +++ b/Service/Service.csproj @@ -1,4 +1,4 @@ - + net7.0 @@ -8,6 +8,7 @@ + diff --git a/Service/ServiceManager.cs b/Service/ServiceManager.cs index 9fe40e6..701266a 100644 --- a/Service/ServiceManager.cs +++ b/Service/ServiceManager.cs @@ -23,16 +23,17 @@ public sealed class ServiceManager : IServiceManager private readonly Lazy _postService; private readonly Lazy _profileService; private readonly Lazy _authenticationService; + - public ServiceManager(IRepositoryManager repositoryManager, IMapper mapper, UserManager userManager, IConfiguration configuration) + public ServiceManager(IRepositoryManager repositoryManager, IMapper mapper, UserManager userManager, IConfiguration configuration, ILoggerFactory loggerFactory) { - _commentService = new Lazy(() => new CommentService(repositoryManager, mapper)); - _likeService = new Lazy(() => new LikeService(repositoryManager, mapper)); - _postPhotoService = new Lazy(() => new PostPhotoService(repositoryManager, mapper)); - _postService = new Lazy(() => new PostService(repositoryManager, mapper)); - _profileService = new Lazy(() => new ProfileService(repositoryManager, mapper)); + _commentService = new Lazy(() => new CommentService(loggerFactory.CreateLogger(), repositoryManager, mapper)); + _likeService = new Lazy(() => new LikeService(loggerFactory.CreateLogger(), repositoryManager, mapper)); + _postPhotoService = new Lazy(() => new PostPhotoService(loggerFactory.CreateLogger(), repositoryManager, mapper)); + _postService = new Lazy(() => new PostService(loggerFactory.CreateLogger(), repositoryManager, mapper)); + _profileService = new Lazy(() => new ProfileService(loggerFactory.CreateLogger(), repositoryManager, mapper)); //_authenticationService = new Lazy(() => new AuthenticationService(logger, mapper, userManager, configuration)); - _authenticationService = new Lazy(() => new AuthenticationService(mapper, userManager, configuration)); + _authenticationService = new Lazy(() => new AuthenticationService(loggerFactory.CreateLogger(), mapper, userManager, configuration)); } public ICommentService CommentService => _commentService.Value; diff --git a/Shared/Shared.csproj b/Shared/Shared.csproj index 253d81e..a950134 100644 --- a/Shared/Shared.csproj +++ b/Shared/Shared.csproj @@ -10,4 +10,8 @@ + + + + From 9bd0e294116e0a52d447cc0b90401170495ff903 Mon Sep 17 00:00:00 2001 From: PC_KYJ Date: Thu, 25 Jan 2024 01:56:26 +0900 Subject: [PATCH 2/5] =?UTF-8?q?Feat:=20JWT=20=ED=86=A0=ED=81=B0=20?= =?UTF-8?q?=EB=B0=9C=EA=B8=89=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/AuthenticationController.cs | 12 +- .../Models/IAuthenticationService.cs | 3 +- Service/Models/AuthenticationService.cs | 136 +++++++++--------- .../Auth/UserAutenticationDto.cs | 15 ++ Shared/Shared.csproj | 4 - 5 files changed, 93 insertions(+), 77 deletions(-) create mode 100644 Shared/DataTransferObject/Auth/UserAutenticationDto.cs diff --git a/EveryPinApi.Presentation/Controllers/AuthenticationController.cs b/EveryPinApi.Presentation/Controllers/AuthenticationController.cs index 0d9c229..ff24a36 100644 --- a/EveryPinApi.Presentation/Controllers/AuthenticationController.cs +++ b/EveryPinApi.Presentation/Controllers/AuthenticationController.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.Logging; using Service.Contracts; using Shared.DataTransferObject; +using Shared.DataTransferObject.Auth; using System; using System.Collections.Generic; using System.Linq; @@ -24,7 +25,7 @@ public AuthenticationController(ILogger logger, IServi _service = service; } - [HttpPost] + [HttpPost("regist")] //[ServiceFilter(typeof(ValidationFilterAttribute))] public async Task RegisterUser([FromBody] RegistUserDto registUserDto) { @@ -42,6 +43,15 @@ public async Task RegisterUser([FromBody] RegistUserDto registUse return StatusCode(201); } + + [HttpPost("login")] + public async Task Authenticate([FromBody] UserAutenticationDto user) + { + if (!await _service.AuthenticationService.ValidateUser(user)) + return Unauthorized(); + + return Ok(new { Token = await _service.AuthenticationService.CreateToken() }); + } } } diff --git a/Service.Contracts/Models/IAuthenticationService.cs b/Service.Contracts/Models/IAuthenticationService.cs index 3c30b1d..b0e5f46 100644 --- a/Service.Contracts/Models/IAuthenticationService.cs +++ b/Service.Contracts/Models/IAuthenticationService.cs @@ -5,13 +5,14 @@ using System.Text; using System.Threading.Tasks; using Shared.DataTransferObject; +using Shared.DataTransferObject.Auth; namespace Service.Contracts.Models { public interface IAuthenticationService { Task RegisterUser(RegistUserDto registUserDto); - Task ValidateUser(); + Task ValidateUser(UserAutenticationDto userForAuths); Task CreateToken(); } diff --git a/Service/Models/AuthenticationService.cs b/Service/Models/AuthenticationService.cs index 73a711d..59a1c85 100644 --- a/Service/Models/AuthenticationService.cs +++ b/Service/Models/AuthenticationService.cs @@ -13,6 +13,7 @@ using System.IdentityModel.Tokens.Jwt; using Microsoft.IdentityModel.Tokens; using Microsoft.Extensions.Logging; +using Shared.DataTransferObject.Auth; namespace Service.Models { @@ -22,9 +23,10 @@ internal sealed class AuthenticationService : IAuthenticationService private readonly IMapper _mapper; private readonly UserManager _userManager; private readonly IConfiguration _configuration; + private User? _user; public AuthenticationService(ILogger logger, IMapper mapper, - UserManager userManager, IConfiguration configuration) + UserManager userManager, IConfiguration configuration) { _logger = logger; _mapper = mapper; @@ -32,84 +34,76 @@ public AuthenticationService(ILogger logger, IMapper mapp _configuration = configuration; } - public Task CreateToken() + public async Task RegisterUser(RegistUserDto registUserDto) { - throw new NotImplementedException(); + var user = _mapper.Map(registUserDto); + var result = await _userManager.CreateAsync(user, registUserDto.Password); + if (result.Succeeded) + await _userManager.AddToRolesAsync(user, registUserDto.Roles); + return result; } + + public async Task ValidateUser(UserAutenticationDto userForAuth) + { + _user = await _userManager.FindByEmailAsync(userForAuth.Email); + //var result = (_user != null && await _userManager.CheckPasswordAsync(_user, userForAuth.Password)); + var result = _user != null; - public Task RegisterUser(RegistUserDto registUserDto) + if (!result) + _logger.LogWarning($"{nameof(ValidateUser)}: 인증 실패. 잘못된 사용자 이름 또는 비밀번호."); + + return result; + } + + public async Task CreateToken() { - throw new NotImplementedException(); + var signingCredentials = GetSigningCredentials(); + var claims = await GetClaims(); + var tokenOptions = GenerateTokenOptions(signingCredentials, claims); + return new JwtSecurityTokenHandler().WriteToken(tokenOptions); } - - public Task ValidateUser() + + private SigningCredentials GetSigningCredentials() + { + var key = Encoding.UTF8.GetBytes(_configuration.GetConnectionString("JwtSettings-SECRET")); + var secret = new SymmetricSecurityKey(key); + return new SigningCredentials(secret, SecurityAlgorithms.HmacSha256); + } + + private async Task> GetClaims() { - throw new NotImplementedException(); + var claims = new List + { + new Claim(ClaimTypes.Email, _user.Email) + }; + + var roles = await _userManager.GetRolesAsync(_user); + foreach (var role in roles) + { + claims.Add(new Claim(ClaimTypes.Role, role)); + } + + return claims; } + + private JwtSecurityToken GenerateTokenOptions(SigningCredentials signingCredentials, List claims) + { + var validIssuer = _configuration.GetConnectionString("JwtSettings-validIssuer"); + var validAudience = _configuration.GetConnectionString("JwtSettings-validAudience"); + var expire = _configuration.GetConnectionString("JwtSettings-expire"); + - //public async Task RegisterUser(RegistUserDto registUserDto) - //{ - // var user = _mapper.Map(registUserDto); - // var result = await _userManager.CreateAsync(user, registUserDto.Password); - // if (result.Succeeded) - // await _userManager.AddToRolesAsync(user, registUserDto.Roles); - // return result; - //} - // - //public async Task ValidateUser(UserForAuthenticationDto userForAuth) - //{ - // _user = await _userManager.FindByNameAsync(userForAuth.UserName); - // var result = (_user != null && await _userManager.CheckPasswordAsync(_user, userForAuth.Password)); - // - // if (!result) - // _logger.LogWarning($"{nameof(ValidateUser)}: 인증 실패. 잘못된 사용자 이름 또는 비밀번호."); - // - // return result; - //} - // - //public async Task CreateToken() - //{ - // var signingCredentials = GetSigningCredentials(); - // var claims = await GetClaims(); - // var tokenOptions = GenerateTokenOptions(signingCredentials, claims); - // return new JwtSecurityTokenHandler().WriteToken(tokenOptions); - //} - // - //private SigningCredentials GetSigningCredentials() - //{ - // var key = Encoding.UTF8.GetBytes(Environment.GetEnvironmentVariable("SECRET")); - // var secret = new SymmetricSecurityKey(key); - // return new SigningCredentials(secret, SecurityAlgorithms.HmacSha256); - //} - // - //private async Task> GetClaims() - //{ - // var claims = new List - // { - // new Claim(ClaimTypes.Name, _user.UserName) - // }; - // - // var roles = await _userManager.GetRolesAsync(_user); - // foreach (var role in roles) - // { - // claims.Add(new Claim(ClaimTypes.Role, role)); - // } - // return claims; - //} - // - //private JwtSecurityToken GenerateTokenOptions(SigningCredentials signingCredentials, List claims) - //{ - // var jwtSettings = _configuration.GetSection("JwtSettings"); - // var tokenOptions = new JwtSecurityToken - // ( - // issuer: jwtSettings["validIssuer"], - // audience: jwtSettings["validAudience"], - // claims: claims, - // expires: DateTime.Now.AddMinutes(Convert.ToDouble(jwtSettings["expires"])), - // signingCredentials: signingCredentials - // ); - // return tokenOptions; - //} + var tokenOptions = new JwtSecurityToken + ( + issuer: validIssuer, + audience: validAudience, + claims: claims, + expires: DateTime.Now.AddMinutes(Convert.ToDouble(expire)), + signingCredentials: signingCredentials + ); + + return tokenOptions; + } } } diff --git a/Shared/DataTransferObject/Auth/UserAutenticationDto.cs b/Shared/DataTransferObject/Auth/UserAutenticationDto.cs new file mode 100644 index 0000000..8c444f1 --- /dev/null +++ b/Shared/DataTransferObject/Auth/UserAutenticationDto.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Shared.DataTransferObject.Auth +{ + public record UserAutenticationDto + { + public string? UserId { get; init; } + public string? Email { get; init; } + public string? PhoneNumber { get; init; } + } +} diff --git a/Shared/Shared.csproj b/Shared/Shared.csproj index a950134..253d81e 100644 --- a/Shared/Shared.csproj +++ b/Shared/Shared.csproj @@ -10,8 +10,4 @@ - - - - From 5110aae5644bfd56aac1a639a123e282d6311753 Mon Sep 17 00:00:00 2001 From: PC_KYJ Date: Sun, 28 Jan 2024 15:44:52 +0900 Subject: [PATCH 3/5] =?UTF-8?q?Feat:=20=EB=A6=AC=ED=94=84=EB=A0=88?= =?UTF-8?q?=EC=8B=9C=20=ED=86=A0=ED=81=B0=20=EB=B0=9C=EA=B8=89=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- EveryPinApi.Entites/Models/User.cs | 2 + .../Controllers/AuthenticationController.cs | 5 +- ...ionalUserFiledsForRefreshToken.Designer.cs | 546 ++++++++++++++++++ ...203_AdditionalUserFiledsForRefreshToken.cs | 80 +++ .../RepositoryContextModelSnapshot.cs | 10 +- .../Models/IAuthenticationService.cs | 2 +- Service/Models/AuthenticationService.cs | 69 ++- Shared/DataTransferObject/Auth/TokenDto.cs | 10 + 8 files changed, 716 insertions(+), 8 deletions(-) create mode 100644 EveryPinApi/Migrations/20240128060203_AdditionalUserFiledsForRefreshToken.Designer.cs create mode 100644 EveryPinApi/Migrations/20240128060203_AdditionalUserFiledsForRefreshToken.cs create mode 100644 Shared/DataTransferObject/Auth/TokenDto.cs diff --git a/EveryPinApi.Entites/Models/User.cs b/EveryPinApi.Entites/Models/User.cs index 3da2003..b627475 100644 --- a/EveryPinApi.Entites/Models/User.cs +++ b/EveryPinApi.Entites/Models/User.cs @@ -17,6 +17,8 @@ public class User : IdentityUser public ICollection Like { get; set; } = new List(); public string? Name { get; set; } //public string? Email { get; set; } + public string? RefreshToken { get; set; } + public DateTime RefreshTokenExpiryTime { get; set; } public DateTime CreatedDate { get; set; } public DateTime LastLoginDate { get; set; } public bool DeleteCheck { get; set; } diff --git a/EveryPinApi.Presentation/Controllers/AuthenticationController.cs b/EveryPinApi.Presentation/Controllers/AuthenticationController.cs index ff24a36..dc3498a 100644 --- a/EveryPinApi.Presentation/Controllers/AuthenticationController.cs +++ b/EveryPinApi.Presentation/Controllers/AuthenticationController.cs @@ -50,7 +50,10 @@ public async Task Authenticate([FromBody] UserAutenticationDto us if (!await _service.AuthenticationService.ValidateUser(user)) return Unauthorized(); - return Ok(new { Token = await _service.AuthenticationService.CreateToken() }); + var tokenDto = await _service.AuthenticationService.CreateToken(populateExp: true); + + return Ok(tokenDto); + } } diff --git a/EveryPinApi/Migrations/20240128060203_AdditionalUserFiledsForRefreshToken.Designer.cs b/EveryPinApi/Migrations/20240128060203_AdditionalUserFiledsForRefreshToken.Designer.cs new file mode 100644 index 0000000..0caeaef --- /dev/null +++ b/EveryPinApi/Migrations/20240128060203_AdditionalUserFiledsForRefreshToken.Designer.cs @@ -0,0 +1,546 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Repository; + +#nullable disable + +namespace EveryPinApi.Migrations +{ + [DbContext(typeof(RepositoryContext))] + [Migration("20240128060203_AdditionalUserFiledsForRefreshToken")] + partial class AdditionalUserFiledsForRefreshToken + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.15") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Entites.Models.CodeOAuthPlatform", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("PlatformCodeId"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("PlatformName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("CodeOAuthPlatforms"); + }); + + modelBuilder.Entity("Entites.Models.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("CommentId"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CommentMessage") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedDate") + .HasColumnType("datetime2"); + + b.Property("PostId") + .HasColumnType("int"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.HasIndex("UserId"); + + b.ToTable("Comments"); + }); + + modelBuilder.Entity("Entites.Models.Like", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("LikeId"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedDate") + .HasColumnType("datetime2"); + + b.Property("PostId") + .HasColumnType("int"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.HasIndex("UserId"); + + b.ToTable("Likes"); + }); + + modelBuilder.Entity("Entites.Models.Post", b => + { + b.Property("PostId") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("PostId"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("PostId")); + + b.Property("CreatedDate") + .HasColumnType("datetime2"); + + b.Property("PostContent") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("PostId"); + + b.ToTable("Posts"); + }); + + modelBuilder.Entity("Entites.Models.PostPhoto", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("PostPhotoId"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("PostId") + .HasColumnType("int"); + + b.Property("photoUrl") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.ToTable("PostPhotos"); + }); + + modelBuilder.Entity("Entites.Models.Profile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("ProfileId"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedDate") + .HasColumnType("datetime2"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.Property("PhotoUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("SelfIntroduction") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Profiles"); + }); + + modelBuilder.Entity("Entites.Models.User", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedDate") + .HasColumnType("datetime2"); + + b.Property("DeleteCheck") + .HasColumnType("bit"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LastLoginDate") + .HasColumnType("datetime2"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("PlatformCodeId") + .HasColumnType("int"); + + b.Property("RefreshToken") + .HasColumnType("nvarchar(max)"); + + b.Property("RefreshTokenExpiryTime") + .HasColumnType("datetime2"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles", (string)null); + + b.HasData( + new + { + Id = "2179ba12-d152-45d3-9d76-d2f5eaca01cf", + Name = "NormalUser", + NormalizedName = "NORMALUSER" + }, + new + { + Id = "8160263c-668a-4495-89dc-35b9296d3a0f", + Name = "Administrator", + NormalizedName = "ADMINISTRATOR" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Entites.Models.Comment", b => + { + b.HasOne("Entites.Models.Post", "Post") + .WithMany("Comments") + .HasForeignKey("PostId"); + + b.HasOne("Entites.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Post"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Entites.Models.Like", b => + { + b.HasOne("Entites.Models.Post", "Post") + .WithMany("Likes") + .HasForeignKey("PostId"); + + b.HasOne("Entites.Models.User", "User") + .WithMany("Like") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Post"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Entites.Models.PostPhoto", b => + { + b.HasOne("Entites.Models.Post", "Post") + .WithMany("PostPhotos") + .HasForeignKey("PostId"); + + b.Navigation("Post"); + }); + + modelBuilder.Entity("Entites.Models.Profile", b => + { + b.HasOne("Entites.Models.User", "User") + .WithOne("Profile") + .HasForeignKey("Entites.Models.Profile", "UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Entites.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Entites.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Entites.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Entites.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Entites.Models.Post", b => + { + b.Navigation("Comments"); + + b.Navigation("Likes"); + + b.Navigation("PostPhotos"); + }); + + modelBuilder.Entity("Entites.Models.User", b => + { + b.Navigation("Like"); + + b.Navigation("Profile"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/EveryPinApi/Migrations/20240128060203_AdditionalUserFiledsForRefreshToken.cs b/EveryPinApi/Migrations/20240128060203_AdditionalUserFiledsForRefreshToken.cs new file mode 100644 index 0000000..a23d850 --- /dev/null +++ b/EveryPinApi/Migrations/20240128060203_AdditionalUserFiledsForRefreshToken.cs @@ -0,0 +1,80 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace EveryPinApi.Migrations +{ + /// + public partial class AdditionalUserFiledsForRefreshToken : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DeleteData( + table: "AspNetRoles", + keyColumn: "Id", + keyValue: "7936c632-4ef6-4ff9-9417-555941ceadd4"); + + migrationBuilder.DeleteData( + table: "AspNetRoles", + keyColumn: "Id", + keyValue: "c5127bc6-4ae3-40e2-b9c9-8c297f6810b1"); + + migrationBuilder.AddColumn( + name: "RefreshToken", + table: "AspNetUsers", + type: "nvarchar(max)", + nullable: true); + + migrationBuilder.AddColumn( + name: "RefreshTokenExpiryTime", + table: "AspNetUsers", + type: "datetime2", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); + + migrationBuilder.InsertData( + table: "AspNetRoles", + columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, + values: new object[,] + { + { "2179ba12-d152-45d3-9d76-d2f5eaca01cf", null, "NormalUser", "NORMALUSER" }, + { "8160263c-668a-4495-89dc-35b9296d3a0f", null, "Administrator", "ADMINISTRATOR" } + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DeleteData( + table: "AspNetRoles", + keyColumn: "Id", + keyValue: "2179ba12-d152-45d3-9d76-d2f5eaca01cf"); + + migrationBuilder.DeleteData( + table: "AspNetRoles", + keyColumn: "Id", + keyValue: "8160263c-668a-4495-89dc-35b9296d3a0f"); + + migrationBuilder.DropColumn( + name: "RefreshToken", + table: "AspNetUsers"); + + migrationBuilder.DropColumn( + name: "RefreshTokenExpiryTime", + table: "AspNetUsers"); + + migrationBuilder.InsertData( + table: "AspNetRoles", + columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, + values: new object[,] + { + { "7936c632-4ef6-4ff9-9417-555941ceadd4", null, "NormalUser", "NORMALUSER" }, + { "c5127bc6-4ae3-40e2-b9c9-8c297f6810b1", null, "Administrator", "ADMINISTRATOR" } + }); + } + } +} diff --git a/EveryPinApi/Migrations/RepositoryContextModelSnapshot.cs b/EveryPinApi/Migrations/RepositoryContextModelSnapshot.cs index f3bad17..4bf12b4 100644 --- a/EveryPinApi/Migrations/RepositoryContextModelSnapshot.cs +++ b/EveryPinApi/Migrations/RepositoryContextModelSnapshot.cs @@ -241,6 +241,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("PlatformCodeId") .HasColumnType("int"); + b.Property("RefreshToken") + .HasColumnType("nvarchar(max)"); + + b.Property("RefreshTokenExpiryTime") + .HasColumnType("datetime2"); + b.Property("SecurityStamp") .HasColumnType("nvarchar(max)"); @@ -293,13 +299,13 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasData( new { - Id = "7936c632-4ef6-4ff9-9417-555941ceadd4", + Id = "2179ba12-d152-45d3-9d76-d2f5eaca01cf", Name = "NormalUser", NormalizedName = "NORMALUSER" }, new { - Id = "c5127bc6-4ae3-40e2-b9c9-8c297f6810b1", + Id = "8160263c-668a-4495-89dc-35b9296d3a0f", Name = "Administrator", NormalizedName = "ADMINISTRATOR" }); diff --git a/Service.Contracts/Models/IAuthenticationService.cs b/Service.Contracts/Models/IAuthenticationService.cs index b0e5f46..8d7e258 100644 --- a/Service.Contracts/Models/IAuthenticationService.cs +++ b/Service.Contracts/Models/IAuthenticationService.cs @@ -13,7 +13,7 @@ public interface IAuthenticationService { Task RegisterUser(RegistUserDto registUserDto); Task ValidateUser(UserAutenticationDto userForAuths); - Task CreateToken(); + Task CreateToken(bool populateExp); } } diff --git a/Service/Models/AuthenticationService.cs b/Service/Models/AuthenticationService.cs index 59a1c85..d145925 100644 --- a/Service/Models/AuthenticationService.cs +++ b/Service/Models/AuthenticationService.cs @@ -14,6 +14,7 @@ using Microsoft.IdentityModel.Tokens; using Microsoft.Extensions.Logging; using Shared.DataTransferObject.Auth; +using System.Security.Cryptography; namespace Service.Models { @@ -55,14 +56,34 @@ public async Task ValidateUser(UserAutenticationDto userForAuth) return result; } - public async Task CreateToken() + //public async Task CreateToken() + //{ + // var signingCredentials = GetSigningCredentials(); + // var claims = await GetClaims(); + // var tokenOptions = GenerateTokenOptions(signingCredentials, claims); + // return new JwtSecurityTokenHandler().WriteToken(tokenOptions); + //} + + public async Task CreateToken(bool populateExp) { var signingCredentials = GetSigningCredentials(); var claims = await GetClaims(); var tokenOptions = GenerateTokenOptions(signingCredentials, claims); - return new JwtSecurityTokenHandler().WriteToken(tokenOptions); + var refreshToken = GenerateRefreshToken(); + + _user.RefreshToken = refreshToken; + + if (populateExp) + _user.RefreshTokenExpiryTime = DateTime.Now.AddDays(7); + + await _userManager.UpdateAsync(_user); + + var accessToken = new JwtSecurityTokenHandler().WriteToken(tokenOptions); + + return new TokenDto(accessToken, refreshToken); } - + + private SigningCredentials GetSigningCredentials() { var key = Encoding.UTF8.GetBytes(_configuration.GetConnectionString("JwtSettings-SECRET")); @@ -104,6 +125,46 @@ private JwtSecurityToken GenerateTokenOptions(SigningCredentials signingCredenti return tokenOptions; } - } + private string GenerateRefreshToken() + { + var randomNumber = new byte[32]; + using (var rng = RandomNumberGenerator.Create()) + { + rng.GetBytes(randomNumber); + return Convert.ToBase64String(randomNumber); + } + } + + private ClaimsPrincipal GetPrincipalFromExpiredToken(string token) + { + var validIssuer = _configuration.GetConnectionString("JwtSettings-validIssuer"); + var validAudience = _configuration.GetConnectionString("JwtSettings-validAudience"); + var key = Encoding.UTF8.GetBytes(_configuration.GetConnectionString("JwtSettings-SECRET")); + + var tokenValidationParameters = new TokenValidationParameters + { + ValidateAudience = true, + ValidateIssuer = true, + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(key), + ValidateLifetime = true, + ValidIssuer = validIssuer, + ValidAudience = validAudience + }; + + var tokenHandler = new JwtSecurityTokenHandler(); + SecurityToken securityToken; + var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out securityToken); + var jwtSecurityToken = securityToken as JwtSecurityToken; + + if (jwtSecurityToken == null || !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase)) + { + throw new SecurityTokenException("Invalid token"); + } + + return principal; + } + + } } diff --git a/Shared/DataTransferObject/Auth/TokenDto.cs b/Shared/DataTransferObject/Auth/TokenDto.cs new file mode 100644 index 0000000..adab6b1 --- /dev/null +++ b/Shared/DataTransferObject/Auth/TokenDto.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Shared.DataTransferObject.Auth +{ + public record TokenDto(string AccessToken, string RefreshToken); +} From f01379496e4e31ef075aced184bd81ee502d121c Mon Sep 17 00:00:00 2001 From: PC_KYJ Date: Sun, 28 Jan 2024 19:14:17 +0900 Subject: [PATCH 4/5] =?UTF-8?q?Feat:=20=ED=86=A0=ED=81=B0=20=EC=BB=A8?= =?UTF-8?q?=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/TokenController.cs | 27 +++++++++++++++++++ .../Models/IAuthenticationService.cs | 1 + Service/Models/AuthenticationService.cs | 13 +++++++++ 3 files changed, 41 insertions(+) create mode 100644 EveryPinApi.Presentation/Controllers/TokenController.cs diff --git a/EveryPinApi.Presentation/Controllers/TokenController.cs b/EveryPinApi.Presentation/Controllers/TokenController.cs new file mode 100644 index 0000000..9ebad34 --- /dev/null +++ b/EveryPinApi.Presentation/Controllers/TokenController.cs @@ -0,0 +1,27 @@ +using Microsoft.AspNetCore.Mvc; +using Service.Contracts; +using Shared.DataTransferObject.Auth; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EveryPinApi.Presentation.Controllers +{ + [Route("api/token")] + [ApiController] + public class TokenController : ControllerBase + { + private readonly IServiceManager _service; + + public TokenController(IServiceManager service) => _service = service; + + [HttpPost("refresh")] + public async Task Refresh([FromBody] TokenDto tokenDto) + { + var tokenDtoToReturn = await _service.AuthenticationService.RefreshToken(tokenDto); + return Ok(tokenDtoToReturn); + } + } +} diff --git a/Service.Contracts/Models/IAuthenticationService.cs b/Service.Contracts/Models/IAuthenticationService.cs index 8d7e258..90a9d1b 100644 --- a/Service.Contracts/Models/IAuthenticationService.cs +++ b/Service.Contracts/Models/IAuthenticationService.cs @@ -14,6 +14,7 @@ public interface IAuthenticationService Task RegisterUser(RegistUserDto registUserDto); Task ValidateUser(UserAutenticationDto userForAuths); Task CreateToken(bool populateExp); + Task RefreshToken(TokenDto tokenDto); } } diff --git a/Service/Models/AuthenticationService.cs b/Service/Models/AuthenticationService.cs index d145925..8b3a429 100644 --- a/Service/Models/AuthenticationService.cs +++ b/Service/Models/AuthenticationService.cs @@ -166,5 +166,18 @@ private ClaimsPrincipal GetPrincipalFromExpiredToken(string token) return principal; } + public async Task RefreshToken(TokenDto tokenDto) + { + var principal = GetPrincipalFromExpiredToken(tokenDto.AccessToken); + var user = await _userManager.FindByNameAsync(principal.Identity.Name); + + if (user == null || user.RefreshToken != tokenDto.RefreshToken || user.RefreshTokenExpiryTime <= DateTime.Now) + //throw new RefreshTokenBadRequest(); + throw new Exception("리프레시 토큰 오류"); + + _user = user; + return await CreateToken(populateExp: false); + } + } } From e86b1cb6e9508d3f00c0a1e2a22a0f9dfc087fe6 Mon Sep 17 00:00:00 2001 From: PC_KYJ Date: Wed, 31 Jan 2024 20:19:24 +0900 Subject: [PATCH 5/5] =?UTF-8?q?Feat:=20=EC=97=AD=ED=95=A0=EA=B8=B0?= =?UTF-8?q?=EB=B0=98=20=EC=9D=B8=EA=B0=80=20=EC=B6=94=EA=B0=80,=20?= =?UTF-8?q?=EB=AA=A8=EB=8D=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- EveryPinApi.Entites/Models/Post.cs | 3 + .../Controllers/AuthenticationController.cs | 3 +- .../Controllers/CommentController.cs | 1 + .../Controllers/LikeController.cs | 4 +- .../Controllers/PostController.cs | 4 +- .../Controllers/PostPhotoController.cs | 4 +- .../Controllers/ProfileController.cs | 4 +- EveryPinApi/EveryPinApi.csproj | 1 + ...20240131103624_AddMapAttribute.Designer.cs | 555 ++++++++++++++++++ .../20240131103624_AddMapAttribute.cs | 88 +++ .../RepositoryContextModelSnapshot.cs | 13 +- EveryPinApi/Program.cs | 31 +- 12 files changed, 702 insertions(+), 9 deletions(-) create mode 100644 EveryPinApi/Migrations/20240131103624_AddMapAttribute.Designer.cs create mode 100644 EveryPinApi/Migrations/20240131103624_AddMapAttribute.cs diff --git a/EveryPinApi.Entites/Models/Post.cs b/EveryPinApi.Entites/Models/Post.cs index a3229ed..da402da 100644 --- a/EveryPinApi.Entites/Models/Post.cs +++ b/EveryPinApi.Entites/Models/Post.cs @@ -14,6 +14,9 @@ public class Post public string? PostContent { get; set; } [ForeignKey("User")] public required string UserId { get; set; } + public string? Address { get; set; } + public double? latitude { get; set; } + public double? longitude { get; set; } public ICollection PostPhotos { get; } = new List(); public ICollection Likes { get; } = new List(); public ICollection Comments { get; } = new List(); diff --git a/EveryPinApi.Presentation/Controllers/AuthenticationController.cs b/EveryPinApi.Presentation/Controllers/AuthenticationController.cs index dc3498a..d388638 100644 --- a/EveryPinApi.Presentation/Controllers/AuthenticationController.cs +++ b/EveryPinApi.Presentation/Controllers/AuthenticationController.cs @@ -29,8 +29,7 @@ public AuthenticationController(ILogger logger, IServi //[ServiceFilter(typeof(ValidationFilterAttribute))] public async Task RegisterUser([FromBody] RegistUserDto registUserDto) { - var result = await - _service.AuthenticationService.RegisterUser(registUserDto); + var result = await _service.AuthenticationService.RegisterUser(registUserDto); if (!result.Succeeded) { diff --git a/EveryPinApi.Presentation/Controllers/CommentController.cs b/EveryPinApi.Presentation/Controllers/CommentController.cs index 8289f9a..61b29c5 100644 --- a/EveryPinApi.Presentation/Controllers/CommentController.cs +++ b/EveryPinApi.Presentation/Controllers/CommentController.cs @@ -26,6 +26,7 @@ public CommentController(ILogger logger, IServiceManager serv } [HttpGet(Name = "GetComment")] + [Authorize(Roles ="NormalUser")] public IActionResult GetAllComment() { var companies = _service.CommentService.GetAllComment(trackChanges: false); diff --git a/EveryPinApi.Presentation/Controllers/LikeController.cs b/EveryPinApi.Presentation/Controllers/LikeController.cs index 0316799..ae897c9 100644 --- a/EveryPinApi.Presentation/Controllers/LikeController.cs +++ b/EveryPinApi.Presentation/Controllers/LikeController.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Service.Contracts; using System; @@ -23,6 +24,7 @@ public LikeController(ILogger logger, IServiceManager service) } [HttpGet] + [Authorize(Roles = "NormalUser")] public IActionResult GetAllLike() { var likes = _service.LikeService.GetAllLike(trackChanges: false); diff --git a/EveryPinApi.Presentation/Controllers/PostController.cs b/EveryPinApi.Presentation/Controllers/PostController.cs index 9089ec7..b9c2fa3 100644 --- a/EveryPinApi.Presentation/Controllers/PostController.cs +++ b/EveryPinApi.Presentation/Controllers/PostController.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Service.Contracts; using System; @@ -23,6 +24,7 @@ public PostController(ILogger logger, IServiceManager service) } [HttpGet] + [Authorize(Roles = "NormalUser")] public IActionResult GetAllPost() { var posts = _service.PostService.GetAllPost(trackChanges: false); diff --git a/EveryPinApi.Presentation/Controllers/PostPhotoController.cs b/EveryPinApi.Presentation/Controllers/PostPhotoController.cs index ad2e76a..11386f1 100644 --- a/EveryPinApi.Presentation/Controllers/PostPhotoController.cs +++ b/EveryPinApi.Presentation/Controllers/PostPhotoController.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Service.Contracts; using System; @@ -23,6 +24,7 @@ public PostPhotoController(ILogger logger, IServiceManager } [HttpGet] + [Authorize(Roles = "NormalUser")] public IActionResult GetAllPostPhoto() { var postPhotos = _service.PostPhotoService.GetAllPostPhoto(trackChanges: false); diff --git a/EveryPinApi.Presentation/Controllers/ProfileController.cs b/EveryPinApi.Presentation/Controllers/ProfileController.cs index 0d0e72e..bd52bb0 100644 --- a/EveryPinApi.Presentation/Controllers/ProfileController.cs +++ b/EveryPinApi.Presentation/Controllers/ProfileController.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Service.Contracts; using System; @@ -23,6 +24,7 @@ public ProfileController(ILogger logger, IServiceManager serv } [HttpGet] + [Authorize(Roles = "NormalUser")] public IActionResult GetAllProfile() { var profiles = _service.ProfileService.GetAllProfile(trackChanges: false); diff --git a/EveryPinApi/EveryPinApi.csproj b/EveryPinApi/EveryPinApi.csproj index 5d23e01..2049ead 100644 --- a/EveryPinApi/EveryPinApi.csproj +++ b/EveryPinApi/EveryPinApi.csproj @@ -16,6 +16,7 @@ + diff --git a/EveryPinApi/Migrations/20240131103624_AddMapAttribute.Designer.cs b/EveryPinApi/Migrations/20240131103624_AddMapAttribute.Designer.cs new file mode 100644 index 0000000..2804433 --- /dev/null +++ b/EveryPinApi/Migrations/20240131103624_AddMapAttribute.Designer.cs @@ -0,0 +1,555 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Repository; + +#nullable disable + +namespace EveryPinApi.Migrations +{ + [DbContext(typeof(RepositoryContext))] + [Migration("20240131103624_AddMapAttribute")] + partial class AddMapAttribute + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.15") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Entites.Models.CodeOAuthPlatform", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("PlatformCodeId"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("PlatformName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("CodeOAuthPlatforms"); + }); + + modelBuilder.Entity("Entites.Models.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("CommentId"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CommentMessage") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedDate") + .HasColumnType("datetime2"); + + b.Property("PostId") + .HasColumnType("int"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.HasIndex("UserId"); + + b.ToTable("Comments"); + }); + + modelBuilder.Entity("Entites.Models.Like", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("LikeId"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedDate") + .HasColumnType("datetime2"); + + b.Property("PostId") + .HasColumnType("int"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.HasIndex("UserId"); + + b.ToTable("Likes"); + }); + + modelBuilder.Entity("Entites.Models.Post", b => + { + b.Property("PostId") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("PostId"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("PostId")); + + b.Property("Address") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedDate") + .HasColumnType("datetime2"); + + b.Property("PostContent") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("latitude") + .HasColumnType("float"); + + b.Property("longitude") + .HasColumnType("float"); + + b.HasKey("PostId"); + + b.ToTable("Posts"); + }); + + modelBuilder.Entity("Entites.Models.PostPhoto", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("PostPhotoId"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("PostId") + .HasColumnType("int"); + + b.Property("photoUrl") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.ToTable("PostPhotos"); + }); + + modelBuilder.Entity("Entites.Models.Profile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("ProfileId"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedDate") + .HasColumnType("datetime2"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.Property("PhotoUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("SelfIntroduction") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Profiles"); + }); + + modelBuilder.Entity("Entites.Models.User", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedDate") + .HasColumnType("datetime2"); + + b.Property("DeleteCheck") + .HasColumnType("bit"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LastLoginDate") + .HasColumnType("datetime2"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("PlatformCodeId") + .HasColumnType("int"); + + b.Property("RefreshToken") + .HasColumnType("nvarchar(max)"); + + b.Property("RefreshTokenExpiryTime") + .HasColumnType("datetime2"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles", (string)null); + + b.HasData( + new + { + Id = "fafbb86f-5268-49e8-a8a0-c35be787f05a", + Name = "NormalUser", + NormalizedName = "NORMALUSER" + }, + new + { + Id = "923a3112-78df-4baf-8127-5aa87babcea7", + Name = "Administrator", + NormalizedName = "ADMINISTRATOR" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Entites.Models.Comment", b => + { + b.HasOne("Entites.Models.Post", "Post") + .WithMany("Comments") + .HasForeignKey("PostId"); + + b.HasOne("Entites.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Post"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Entites.Models.Like", b => + { + b.HasOne("Entites.Models.Post", "Post") + .WithMany("Likes") + .HasForeignKey("PostId"); + + b.HasOne("Entites.Models.User", "User") + .WithMany("Like") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Post"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Entites.Models.PostPhoto", b => + { + b.HasOne("Entites.Models.Post", "Post") + .WithMany("PostPhotos") + .HasForeignKey("PostId"); + + b.Navigation("Post"); + }); + + modelBuilder.Entity("Entites.Models.Profile", b => + { + b.HasOne("Entites.Models.User", "User") + .WithOne("Profile") + .HasForeignKey("Entites.Models.Profile", "UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Entites.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Entites.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Entites.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Entites.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Entites.Models.Post", b => + { + b.Navigation("Comments"); + + b.Navigation("Likes"); + + b.Navigation("PostPhotos"); + }); + + modelBuilder.Entity("Entites.Models.User", b => + { + b.Navigation("Like"); + + b.Navigation("Profile"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/EveryPinApi/Migrations/20240131103624_AddMapAttribute.cs b/EveryPinApi/Migrations/20240131103624_AddMapAttribute.cs new file mode 100644 index 0000000..b1eeb4b --- /dev/null +++ b/EveryPinApi/Migrations/20240131103624_AddMapAttribute.cs @@ -0,0 +1,88 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace EveryPinApi.Migrations +{ + /// + public partial class AddMapAttribute : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DeleteData( + table: "AspNetRoles", + keyColumn: "Id", + keyValue: "2179ba12-d152-45d3-9d76-d2f5eaca01cf"); + + migrationBuilder.DeleteData( + table: "AspNetRoles", + keyColumn: "Id", + keyValue: "8160263c-668a-4495-89dc-35b9296d3a0f"); + + migrationBuilder.AddColumn( + name: "Address", + table: "Posts", + type: "nvarchar(max)", + nullable: true); + + migrationBuilder.AddColumn( + name: "latitude", + table: "Posts", + type: "float", + nullable: true); + + migrationBuilder.AddColumn( + name: "longitude", + table: "Posts", + type: "float", + nullable: true); + + migrationBuilder.InsertData( + table: "AspNetRoles", + columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, + values: new object[,] + { + { "923a3112-78df-4baf-8127-5aa87babcea7", null, "Administrator", "ADMINISTRATOR" }, + { "fafbb86f-5268-49e8-a8a0-c35be787f05a", null, "NormalUser", "NORMALUSER" } + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DeleteData( + table: "AspNetRoles", + keyColumn: "Id", + keyValue: "923a3112-78df-4baf-8127-5aa87babcea7"); + + migrationBuilder.DeleteData( + table: "AspNetRoles", + keyColumn: "Id", + keyValue: "fafbb86f-5268-49e8-a8a0-c35be787f05a"); + + migrationBuilder.DropColumn( + name: "Address", + table: "Posts"); + + migrationBuilder.DropColumn( + name: "latitude", + table: "Posts"); + + migrationBuilder.DropColumn( + name: "longitude", + table: "Posts"); + + migrationBuilder.InsertData( + table: "AspNetRoles", + columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, + values: new object[,] + { + { "2179ba12-d152-45d3-9d76-d2f5eaca01cf", null, "NormalUser", "NORMALUSER" }, + { "8160263c-668a-4495-89dc-35b9296d3a0f", null, "Administrator", "ADMINISTRATOR" } + }); + } + } +} diff --git a/EveryPinApi/Migrations/RepositoryContextModelSnapshot.cs b/EveryPinApi/Migrations/RepositoryContextModelSnapshot.cs index 4bf12b4..1ab87e2 100644 --- a/EveryPinApi/Migrations/RepositoryContextModelSnapshot.cs +++ b/EveryPinApi/Migrations/RepositoryContextModelSnapshot.cs @@ -108,6 +108,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("PostId")); + b.Property("Address") + .HasColumnType("nvarchar(max)"); + b.Property("CreatedDate") .HasColumnType("datetime2"); @@ -121,6 +124,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired() .HasColumnType("nvarchar(max)"); + b.Property("latitude") + .HasColumnType("float"); + + b.Property("longitude") + .HasColumnType("float"); + b.HasKey("PostId"); b.ToTable("Posts"); @@ -299,13 +308,13 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasData( new { - Id = "2179ba12-d152-45d3-9d76-d2f5eaca01cf", + Id = "fafbb86f-5268-49e8-a8a0-c35be787f05a", Name = "NormalUser", NormalizedName = "NORMALUSER" }, new { - Id = "8160263c-668a-4495-89dc-35b9296d3a0f", + Id = "923a3112-78df-4baf-8127-5aa87babcea7", Name = "Administrator", NormalizedName = "ADMINISTRATOR" }); diff --git a/EveryPinApi/Program.cs b/EveryPinApi/Program.cs index f014fe3..460ba76 100644 --- a/EveryPinApi/Program.cs +++ b/EveryPinApi/Program.cs @@ -2,6 +2,9 @@ using Service; using Microsoft.AspNetCore.HttpOverrides; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.OpenApi.Models; var builder = WebApplication.CreateBuilder(args); { @@ -17,7 +20,33 @@ // Swagger/OpenAPI builder.Services.AddEndpointsApiExplorer(); - builder.Services.AddSwaggerGen(); + builder.Services.AddSwaggerGen(option => + { + option.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" }); + option.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme + { + In = ParameterLocation.Header, + Description = "Please enter a valid token", + Name = "Authorization", + Type = SecuritySchemeType.Http, + BearerFormat = "JWT", + Scheme = JwtBearerDefaults.AuthenticationScheme + }); + option.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = JwtBearerDefaults.AuthenticationScheme + } + }, + new string[]{} + } + }); + }); // Azure Logging builder.Logging.AddAzureWebAppDiagnostics();