diff --git a/Back.csproj b/Back.csproj index b289ad8..09c7865 100644 --- a/Back.csproj +++ b/Back.csproj @@ -20,6 +20,13 @@ + + + + + + <_ContentIncludedByDefault Remove="wwwroot\css\app.css" /> + <_ContentIncludedByDefault Remove="wwwroot\css\tailwind.css" /> diff --git a/Program.cs b/Program.cs index 58404cd..eb7e97d 100644 --- a/Program.cs +++ b/Program.cs @@ -127,7 +127,7 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); -// builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); diff --git a/Program/Common/Auth/APIHeaderMiddleware.cs b/Program/Common/Auth/APIHeaderMiddleware.cs index a4a26fb..f128074 100644 --- a/Program/Common/Auth/APIHeaderMiddleware.cs +++ b/Program/Common/Auth/APIHeaderMiddleware.cs @@ -24,6 +24,13 @@ namespace Back.Program.Common.Auth await _next(context); return; } + + if (context.Request.Path.Value != null && context.Request.Path.Value.Contains("/out/")) + { + await _next(context); + return; + } + // 정적 파일 요청은 미들웨어 건너뜀 var path = context.Request.Path.Value; @@ -58,12 +65,11 @@ namespace Back.Program.Common.Auth } await _next(context); - } - - { - await _next(context); return; } + + await _next(context); + } } } \ No newline at end of file diff --git a/Program/Controllers/V1/OutController.cs b/Program/Controllers/V1/OutController.cs new file mode 100644 index 0000000..b5bbfc8 --- /dev/null +++ b/Program/Controllers/V1/OutController.cs @@ -0,0 +1,64 @@ +using System.Text.Json; +using Back.Program.Controllers.V1; +using Back.Program.Services.V1; +using Back.Program.Services.V1.Interfaces; +using Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.AspNetCore.Mvc; + +namespace Back.Program.Controllers; + +[ApiController] +[Route("/api/v1/out/user")] +[ApiExplorerSettings(GroupName = "외부 동작(사용자)")] +public class OutController: ControllerBase +{ + private readonly ILogger _logger; + private readonly IRepositoryService _repositoryService; + private readonly IUserService _userService; + private readonly IKakaoService _kakaoService; + + public OutController(ILogger logger, + IRepositoryService repositoryService, IUserService userService, IKakaoService kakaoService) + { + _logger = logger; + _repositoryService = repositoryService; + _userService = userService; + _kakaoService = kakaoService; + } + [HttpGet("kakao/auth")] + [CustomOperation("카카오 로그인", "카카오 로그인 동작", "사용자")] + public async Task KakaoLogin([FromQuery] string? scope) + { + var url = await _kakaoService.GetAuthorizationUrl(scope ?? ""); + Console.WriteLine($"카카오 로그인 API: {url}"); + return Ok(new { url }); + } + + [HttpGet("kakao/redirect")] + public async Task RedirectFromKakao([FromQuery] string code) + { + var (success, response) = await _kakaoService.Redirect(code); + Console.WriteLine($"리다이렉트 : {response}"); + if (success) + { + // HttpContext.Session.SetString("AccessToken", response); + var (idSuccess, idResponse) = await _kakaoService.UserMe(response); + if (idSuccess) + { + var json = JsonDocument.Parse(idResponse); + if (json.RootElement.TryGetProperty("id", out var idElement)) + { + var snsId = idElement.ToString(); + Console.WriteLine($"ID = {snsId}"); + var loginResult = await _userService.Login("SNS Login", "ST01", snsId); + Console.WriteLine($"login = {loginResult.JsonToString()}"); + // return Ok(new { id="cc" }); + } + } + Console.WriteLine($"ID_res = {idResponse}"); + + } + return BadRequest(); + + } +} \ No newline at end of file diff --git a/Program/Controllers/V1/UserController.cs b/Program/Controllers/V1/UserController.cs index b4ec050..93fe848 100644 --- a/Program/Controllers/V1/UserController.cs +++ b/Program/Controllers/V1/UserController.cs @@ -5,6 +5,7 @@ using Back.Program.Common.Model; using Back.Program.Models.Entities; using Back.Program.Services.V1.Interfaces; using Back.Program.Services.V1; +using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -21,7 +22,6 @@ namespace Back.Program.Controllers.V1 private readonly ILogger _logger; private readonly IRepositoryService _repositoryService; private readonly IUserService _userService; - private readonly IKakaoService _kakaoService; public UserController(ILogger logger, IRepositoryService repositoryService, IUserService userService, IKakaoService kakaoService) @@ -29,7 +29,6 @@ namespace Back.Program.Controllers.V1 _logger = logger; _repositoryService = repositoryService; _userService = userService; - _kakaoService = kakaoService; } [HttpGet] @@ -106,15 +105,12 @@ namespace Back.Program.Controllers.V1 var result = await _userService.GetAcademy(summary, token); return Ok(result); } + + - [HttpGet("kakao/auth")] - [CustomOperation("카카오 로그인", "카카오 로그인 동작", "사용자")] - public async Task KakaoLogin([FromQuery] string scope) - { - var authUrl = await _kakaoService.GetAuthorizationUrl(scope); - return Redirect(authUrl); - } + + } } @@ -122,7 +118,7 @@ namespace Back.Program.Controllers.V1 // 근데 회원 정보를 변경하는게 뭐뭐를 변경해야 하는지 아직 정해진게 없어서 이건 일단 보류 /* [HttpGet("set")] - [CustomOperation("회원 정보 변경", "회원 정보 변경", "사용자")] + [CustomOperation("회원 정보 변경", "회원 정보 변경", "사혹자")] public async Task SetUserData(string token, string refresh) //, [FromBody]) { if (string.IsNullOrEmpty(token) || string.IsNullOrEmpty(refresh)) diff --git a/Program/Services/V1/Interfaces/IKakaoService.cs b/Program/Services/V1/Interfaces/IKakaoService.cs index e24f23e..d3ae355 100644 --- a/Program/Services/V1/Interfaces/IKakaoService.cs +++ b/Program/Services/V1/Interfaces/IKakaoService.cs @@ -9,4 +9,5 @@ public interface IKakaoService Task<(bool Success, string Response)> Redirect(string code); Task<(bool Success, string Response)> Logout(string accessToken); Task<(bool Success, string Response)> Unlink(string accessToken); + Task<(bool Success, string Response)> UserMe(string accessToken); } \ No newline at end of file diff --git a/Program/Services/V1/KakaoService.cs b/Program/Services/V1/KakaoService.cs index efffa87..05ad33d 100644 --- a/Program/Services/V1/KakaoService.cs +++ b/Program/Services/V1/KakaoService.cs @@ -53,6 +53,11 @@ public class KakaoService: IKakaoService } } + /// + /// 인가 받은 코드로 토큰 받기를 실행하고 이 토큰으로 사용자 정보 가져오기를 할 수 있다. + /// + /// + /// public async Task GetAccessToken(string code) { var content = new FormUrlEncodedContent(new[] @@ -81,6 +86,13 @@ public class KakaoService: IKakaoService return JsonSerializer.Serialize(new { access_token = accessToken.GetString() }); } + + /// + /// 인가코드를 받는다 이 인가코드를 사용해 토큰 받기를 요청 할 수 있다. + /// 이게 리다이렉트에 포함되어있음 + /// + /// + /// public Task GetAuthorizationUrl(string scope) { var authUrl = $"{KAKAO_AUTH_BASE_URL}/oauth/authorize?client_id={_clientId}&redirect_uri={_redirectUri}&response_type=code"; @@ -132,4 +144,14 @@ public class KakaoService: IKakaoService var response = await Call(HttpMethod.Post, $"{KAKAO_API_BASE_URL}/v1/user/unlink"); return (true, response); } + + public async Task<(bool Success, string Response)> UserMe(string accessToken) + { + if (string.IsNullOrEmpty(accessToken)) + return (false, JsonSerializer.Serialize(new { error = "Not logged in" })); + + SetHeaders(accessToken); + var response = await Call(HttpMethod.Get, $"{KAKAO_API_BASE_URL}/v2/user/me"); + return (true, response); + } } \ No newline at end of file diff --git a/Program/Services/V1/RepositoryService.cs b/Program/Services/V1/RepositoryService.cs index 9313c4a..875ac1b 100644 --- a/Program/Services/V1/RepositoryService.cs +++ b/Program/Services/V1/RepositoryService.cs @@ -1,5 +1,7 @@ using System.Linq.Expressions; using System.Reflection; +using System.Text; +using System.Text.Json; using Back.Program.Common.Auth; using Back.Program.Common.Data; using Back.Program.Common.Model; @@ -14,6 +16,7 @@ namespace Back.Program.Services.V1 Task SaveData(T entity, Expression> key = null) where T : class; Task DeleteData(T entity, Expression> key = null) where T : class; String ReadSummary(Type type, String name); + Task SendFrontData(T data, string url); } public class RepositoryService: IRepositoryService @@ -28,61 +31,6 @@ namespace Back.Program.Services.V1 _logger = logger; _jwtTokenService = jwtTokenService; } - - - // public async Task ValidateToken(string token, string refresh) - // { - // var principalToken = await _jwtTokenService.ValidateToken(token); - // if (principalToken != null) - // { - // var uid = principalToken.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? string.Empty; - // _logger.LogInformation($"토큰 변환 - {uid}"); - // return new ValidateToken - // { - // token = token, - // refresh = refresh, - // uid = uid - // }; - // } - // else - // { - // _logger.LogInformation("엑세스 토큰 만료"); - // // var refreshToken = await _dbContext.RefreshTokens - // // .FirstOrDefaultAsync(t => t.refresh_token == refresh); - // // if (refreshToken == null) - // // throw new TokenException("입력 받은 토큰 자체의 문제"); - // // - // // var uid = refreshToken.uid; - // // - // // if (refreshToken.revoke_Date < DateTime.Now) - // // throw new RefreshRevokeException("리프레시 토큰 해지"); - // // - // // if (refreshToken.expire_date > DateTime.Now) - // // { - // // _logger.LogInformation($"인증 완료 리프레시 : {uid}"); - // // var access = _jwtTokenService.GenerateJwtToken(uid); - // // - // // return new ValidateToken - // // { - // // token = access, - // // refresh = refreshToken.refresh_token, - // // uid = uid - // // }; - // // } - // // else - // // { - // // refreshToken = _jwtTokenService.GenerateRefreshToken(uid); - // // _logger.LogInformation("리프레시 토큰 만료"); - // // // await SaveData(refreshToken, rt => rt.uid); - // // return new ValidateToken - // // { - // // token = token, - // // refresh = refreshToken.refresh_token, - // // uid = uid - // // }; - // // } - // } - // } public async Task SaveData(T entity, Expression> key = null) where T : class { @@ -227,5 +175,14 @@ namespace Back.Program.Services.V1 var att = method.GetCustomAttribute() ?? throw new AcaException(ResposeCode.NetworkErr,"swagger summary Load ERROR: NULL"); return att.Summary; } + + public async Task SendFrontData(T data, string url) + { + using var httpClient = new HttpClient(); + var json = JsonSerializer.Serialize(data); + var content = new StringContent(json, Encoding.UTF8, "application/json"); + var response = await httpClient.PostAsync(url, content); + response.EnsureSuccessStatusCode(); + } } } diff --git a/appsettings.Development.json b/appsettings.Development.json index ff14d6a..56092aa 100644 --- a/appsettings.Development.json +++ b/appsettings.Development.json @@ -7,8 +7,15 @@ }, "PushFileSetting": { "uri": "https://api.sandbox.push.apple.com/", - "p12Path": "/src/private/AM_Push_Sandbox.p12", - "p12PWPath": "/src/private/appleKeys.json", + "p12Path": "./private/AM_Push_Sandbox.p12", + "p12PWPath": "./private/appleKeys.json", "apnsTopic": "me.myds.ipstein.acamate.AcaMate" + }, + "AllowedHosts": "*", + "Kakao": { + "ClientId": "a9632e6c14d8706ef6c8fe2ef52b721d", + "ClientSecret": " this is rest api secret key ", + "RedirectUri": "http://0.0.0.0:5144/api/v1/out/user/kakao/redirect" +// "RedirectUri": "https://acamate.ipstein.com/kakao" } } diff --git a/appsettings.json b/appsettings.json index 056faaf..0d1d341 100644 --- a/appsettings.json +++ b/appsettings.json @@ -11,10 +11,10 @@ "P12PWPath": "/src/private/appleKeys.json", "ApnsTopic": "me.myds.ipstein.acamate.AcaMate" }, - "AllowedHosts": "*" -// "Kakao": { -// "ClientId": "a9632e6c14d8706ef6c8fe2ef52b721d", -// "ClientSecret": " this is rest api secret key ", -// "RedirectUri": "https://acamate.ipstein.com/kakao" -// } + "AllowedHosts": "*", + "Kakao": { + "ClientId": "a9632e6c14d8706ef6c8fe2ef52b721d", + "ClientSecret": " this is rest api secret key ", + "RedirectUri": "https://acamate.ipstein.com/kakao" + } } \ No newline at end of file