From 50f740aa4b4361ad8ee801609e84b84129e7c42c Mon Sep 17 00:00:00 2001 From: Seonkyu_Kim Date: Tue, 18 Mar 2025 17:54:04 +0900 Subject: [PATCH] =?UTF-8?q?[=E2=9C=A8]=20API=20Header=20=EC=A0=90=EA=B2=80?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Back.csproj | 4 -- Program.cs | 15 +++++- Program/Common/Auth/APIHeaderFilter.cs | 27 +++++++++++ Program/Common/Auth/APIHeaderMiddle.cs | 65 ++++++++++++++++++++++++++ Program/Common/Data/AppDbContext.cs | 3 ++ Program/Common/Model/APISetting.cs | 19 ++++++++ 6 files changed, 127 insertions(+), 6 deletions(-) create mode 100644 Program/Common/Auth/APIHeaderFilter.cs create mode 100644 Program/Common/Auth/APIHeaderMiddle.cs create mode 100644 Program/Common/Model/APISetting.cs diff --git a/Back.csproj b/Back.csproj index fc3d551..f591412 100644 --- a/Back.csproj +++ b/Back.csproj @@ -18,9 +18,5 @@ - - - - diff --git a/Program.cs b/Program.cs index c2501c8..3399e82 100644 --- a/Program.cs +++ b/Program.cs @@ -14,6 +14,7 @@ using System.Text.Json; using AcaMate.Common.Models; using AcaMate.V1.Services; using AcaMate.Common.Data; +using AcaMate.Common.Token; using AcaMate.V1.Controllers; using AcaMate.V1.Models; @@ -149,10 +150,13 @@ else builder.Logging.SetMinimumLevel(LogLevel.Warning); } +//헤더 부분 +builder.Services.AddScoped(); + // 로컬 테스트 위한 부분 (올릴때는 꺼두기) -// builder.WebHost.UseUrls("http://0.0.0.0:5144"); +builder.WebHost.UseUrls("http://0.0.0.0:5144"); ///// ===== builder 설정 부 ===== ///// @@ -172,7 +176,14 @@ else } // 로컬 테스트 위한 부분 (올릴떄는 켜두기) -app.UseHttpsRedirection(); +// app.UseHttpsRedirection(); + +// 헤더 미들웨어 부분 +app.UseMiddleware("HEAD-CHECK"); + +// 이부분 봐야 합니다. +// app.UseMiddleware("X-MyHeader"); + app.UseRouting(); // app.MapControllers(); diff --git a/Program/Common/Auth/APIHeaderFilter.cs b/Program/Common/Auth/APIHeaderFilter.cs new file mode 100644 index 0000000..766fba0 --- /dev/null +++ b/Program/Common/Auth/APIHeaderFilter.cs @@ -0,0 +1,27 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; + + +namespace AcaMate.Common.Token; + +public class APIHeaderFilter : ActionFilterAttribute +{ + private readonly string _headerName; + + public APIHeaderFilter(string headerName) + { + _headerName = headerName; + } + + public override void OnActionExecuted(ActionExecutedContext context) + { + if (!context.HttpContext.Request.Headers.TryGetValue(_headerName, out var headerValues) || + string.IsNullOrWhiteSpace(headerValues)) + { + context.Result = new BadRequestObjectResult($"Missing or empty header: {_headerName}"); + } + + base.OnActionExecuted(context); + } + +} \ No newline at end of file diff --git a/Program/Common/Auth/APIHeaderMiddle.cs b/Program/Common/Auth/APIHeaderMiddle.cs new file mode 100644 index 0000000..7d5fcc2 --- /dev/null +++ b/Program/Common/Auth/APIHeaderMiddle.cs @@ -0,0 +1,65 @@ +using System.Threading.Tasks; +using AcaMate.Common.Data; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore; + +namespace AcaMate.Common.Token; +public interface IHeaderConfig +{ + Task GetExpectedHeaderValueAsync(string headerName); +} + +public class HeaderConfigRepository : IHeaderConfig +{ + private readonly AppDbContext _dbContext; + + public HeaderConfigRepository(AppDbContext dbContext) + { + _dbContext = dbContext; + } + + public async Task GetExpectedHeaderValueAsync(string headerName) + { + // 예를 들어, HeaderConfig 테이블에 헤더 이름과 기대 값이 저장되어 있다고 가정합니다. + var config = await _dbContext.APIHeader. + FirstOrDefaultAsync(h => h.h_key == headerName); + return config?.h_value ?? string.Empty; + } +} + + +public class APIHeaderMiddle +{ + + private readonly RequestDelegate _next; + private readonly string _headerName; + private readonly IHeaderConfig _headerConfig; + + public APIHeaderMiddle(RequestDelegate next, string headerName, IHeaderConfig headerConfig) + { + _next = next; + _headerName = headerName; + _headerConfig = headerConfig; + } + + public async Task Invoke(HttpContext context) + { + var expectedValue = await _headerConfig.GetExpectedHeaderValueAsync(_headerName); + + if (!context.Request.Headers.TryGetValue(_headerName,out var headerValue) || string.IsNullOrWhiteSpace(headerValue)) + // if (!context.Request.Headers.ContainsKey(_headerName) || string.IsNullOrWhiteSpace(context.Request.Headers[_headerName])) + { + context.Response.StatusCode = StatusCodes.Status400BadRequest; + await context.Response.WriteAsync($"Missing or empty header: {_headerName}"); + return; + } + + if (headerValue != expectedValue) + { + context.Response.StatusCode = StatusCodes.Status401Unauthorized; + await context.Response.WriteAsync($"Invalid header value"); + return; + } + await _next(context); + } +} \ No newline at end of file diff --git a/Program/Common/Data/AppDbContext.cs b/Program/Common/Data/AppDbContext.cs index dd2a32a..08a5c95 100644 --- a/Program/Common/Data/AppDbContext.cs +++ b/Program/Common/Data/AppDbContext.cs @@ -11,6 +11,9 @@ public class AppDbContext: DbContext { } + //MARK: API + public DbSet APIHeader { get; set; } + //MARK: Program public DbSet Version { get; set; } public DbSet Academy { get; set; } diff --git a/Program/Common/Model/APISetting.cs b/Program/Common/Model/APISetting.cs new file mode 100644 index 0000000..e26c6fd --- /dev/null +++ b/Program/Common/Model/APISetting.cs @@ -0,0 +1,19 @@ +using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel.DataAnnotations; + +namespace AcaMate.Common.Models; + +[Table("api_header")] +public class APIHeader +{ + [Key] + public string h_key { get; set; } + public string h_value { get; set; } +} + +/* + h_key : h_value + iOS_AM_Connect_Key + And_AM_Connect_Key + Web_AM_Connect_Key +*/ \ No newline at end of file