Image Upload In ASP.NET Core Web API

1. Domain Model 생성

Image.cs

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
using System.ComponentModel.DataAnnotations.Schema;
namespace NZWalks.API.Models.Domain
{
public class Image
{
public Guid Id { get; set; } // 이미지의 고유 식별자
[NotMapped] // Entity Framework가 해당 속성을 데이터베이스 테이블에 매핑하지 않도록 지정
public IFormFile File { get; set; } // File Data 객체를 나타내는 IFormFile 객체
public string Filename { get; set; } // 파일 이름
public string? FileDescription { get; set; } // 파일 설명 (nullable)
public string FileExtension { get; set; } // 파일 확장자 (예: .jpg, .png)
public long FileSizeInBytes { get; set; } // 파일 크기 (바이트 단위)
public string FilePath { get; set; } // 파일 저장 경로
}
}
using System.ComponentModel.DataAnnotations.Schema; namespace NZWalks.API.Models.Domain { public class Image { public Guid Id { get; set; } // 이미지의 고유 식별자 [NotMapped] // Entity Framework가 해당 속성을 데이터베이스 테이블에 매핑하지 않도록 지정 public IFormFile File { get; set; } // File Data 객체를 나타내는 IFormFile 객체 public string Filename { get; set; } // 파일 이름 public string? FileDescription { get; set; } // 파일 설명 (nullable) public string FileExtension { get; set; } // 파일 확장자 (예: .jpg, .png) public long FileSizeInBytes { get; set; } // 파일 크기 (바이트 단위) public string FilePath { get; set; } // 파일 저장 경로 } }
using System.ComponentModel.DataAnnotations.Schema;

namespace NZWalks.API.Models.Domain
{
    public class Image
    {
        public Guid Id { get; set; } // 이미지의 고유 식별자

        [NotMapped] // Entity Framework가 해당 속성을 데이터베이스 테이블에 매핑하지 않도록 지정
        public IFormFile File { get; set; } // File Data 객체를 나타내는 IFormFile 객체

        public string Filename { get; set; } // 파일 이름
        public string? FileDescription { get; set; } // 파일 설명 (nullable)
        public string FileExtension { get; set; } // 파일 확장자 (예: .jpg, .png)
        public long FileSizeInBytes { get; set; } // 파일 크기 (바이트 단위)
        public string FilePath { get; set; } // 파일 저장 경로
    }
}

2. DBContext 생성

Image DbSet 추가
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Package Manager Console
Add-Migration "Adding Images Table" -Context "NZWalksDbcontext"
Update-Database -Context "NZWalksDbcontext"
// Package Manager Console Add-Migration "Adding Images Table" -Context "NZWalksDbcontext" Update-Database -Context "NZWalksDbcontext"
// Package Manager Console 

Add-Migration "Adding Images Table" -Context "NZWalksDbcontext"
Update-Database -Context "NZWalksDbcontext"

3. Image Controller 및 Method 생성

ImageController.cs

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
using Microsoft.AspNetCore.Mvc;
using NZWalks.API.Models.Domain;
using NZWalks.API.Models.DTO;
using NZWalks.API.Repositories;
namespace NZWalks.API.Controllers
{
[Route("api/[controller]")] // 컨트롤러의 기본 경로를 설정. [controller]는 컨트롤러 이름으로 대체됨.
[ApiController] // API 컨트롤러 특성 적용
public class ImageController : ControllerBase
{
private readonly IImageRepository imageRepository;
// IImageRepository를 주입받아 초기화
public ImageController(IImageRepository imageRepository)
{
this.imageRepository = imageRepository;
}
// POST: /api/Images/Upload
[HttpPost]
[Route("Upload")]
public async Task<IActionResult> Upload([FromForm] ImageUploadRequestDto request)
{
// 파일 업로드 유효성 검사
ValidateFileUpload(request);
if (ModelState.IsValid)
{
// DTO를 도메인 모델로 변환
var imageDomainModel = new Image
{
File = request.File,
FileExtension = Path.GetExtension(request.File.FileName),
FileSizeInBytes = request.File.Length,
Filename = request.File.FileName,
FileDescription = request.FileDescription
};
// 이미지 업로드를 위해 리포지토리 사용
await imageRepository.Uploade(imageDomainModel);
return Ok(imageDomainModel); // 업로드된 이미지 정보 반환
}
return BadRequest(ModelState); // 유효성 검사 실패 시 오류 반환
}
// 파일 업로드 유효성 검사 메서드
private void ValidateFileUpload(ImageUploadRequestDto request)
{
var allowedExtensions = new string[] { ".jpg", ".jpeg", ".Png" }; // 허용되는 확장자 목록
// 파일 확장자 검사
if (!allowedExtensions.Contains(Path.GetExtension(request.File.FileName)))
{
ModelState.AddModelError("file", "Unsupported file extension"); // 지원되지 않는 파일 확장자 오류 추가
}
// 파일 크기 검사 (10MB 초과 여부)
if (request.File.Length > 10485760) // 10MB
{
ModelState.AddModelError("file", "File Size more than 10MB, Please upload a smaller size file"); // 파일 크기 초과 오류 추가
}
}
}
}
using Microsoft.AspNetCore.Mvc; using NZWalks.API.Models.Domain; using NZWalks.API.Models.DTO; using NZWalks.API.Repositories; namespace NZWalks.API.Controllers { [Route("api/[controller]")] // 컨트롤러의 기본 경로를 설정. [controller]는 컨트롤러 이름으로 대체됨. [ApiController] // API 컨트롤러 특성 적용 public class ImageController : ControllerBase { private readonly IImageRepository imageRepository; // IImageRepository를 주입받아 초기화 public ImageController(IImageRepository imageRepository) { this.imageRepository = imageRepository; } // POST: /api/Images/Upload [HttpPost] [Route("Upload")] public async Task<IActionResult> Upload([FromForm] ImageUploadRequestDto request) { // 파일 업로드 유효성 검사 ValidateFileUpload(request); if (ModelState.IsValid) { // DTO를 도메인 모델로 변환 var imageDomainModel = new Image { File = request.File, FileExtension = Path.GetExtension(request.File.FileName), FileSizeInBytes = request.File.Length, Filename = request.File.FileName, FileDescription = request.FileDescription }; // 이미지 업로드를 위해 리포지토리 사용 await imageRepository.Uploade(imageDomainModel); return Ok(imageDomainModel); // 업로드된 이미지 정보 반환 } return BadRequest(ModelState); // 유효성 검사 실패 시 오류 반환 } // 파일 업로드 유효성 검사 메서드 private void ValidateFileUpload(ImageUploadRequestDto request) { var allowedExtensions = new string[] { ".jpg", ".jpeg", ".Png" }; // 허용되는 확장자 목록 // 파일 확장자 검사 if (!allowedExtensions.Contains(Path.GetExtension(request.File.FileName))) { ModelState.AddModelError("file", "Unsupported file extension"); // 지원되지 않는 파일 확장자 오류 추가 } // 파일 크기 검사 (10MB 초과 여부) if (request.File.Length > 10485760) // 10MB { ModelState.AddModelError("file", "File Size more than 10MB, Please upload a smaller size file"); // 파일 크기 초과 오류 추가 } } } }
using Microsoft.AspNetCore.Mvc;
using NZWalks.API.Models.Domain;
using NZWalks.API.Models.DTO;
using NZWalks.API.Repositories;

namespace NZWalks.API.Controllers
{
    [Route("api/[controller]")] // 컨트롤러의 기본 경로를 설정. [controller]는 컨트롤러 이름으로 대체됨.
    [ApiController] // API 컨트롤러 특성 적용
    public class ImageController : ControllerBase
    {
        private readonly IImageRepository imageRepository;

        // IImageRepository를 주입받아 초기화
        public ImageController(IImageRepository imageRepository)
        {
            this.imageRepository = imageRepository;
        }

        // POST: /api/Images/Upload
        [HttpPost]
        [Route("Upload")]
        public async Task<IActionResult> Upload([FromForm] ImageUploadRequestDto request)
        {
            // 파일 업로드 유효성 검사
            ValidateFileUpload(request);

            if (ModelState.IsValid)
            {
                // DTO를 도메인 모델로 변환
                var imageDomainModel = new Image
                {
                    File = request.File,
                    FileExtension = Path.GetExtension(request.File.FileName),
                    FileSizeInBytes = request.File.Length,
                    Filename = request.File.FileName,
                    FileDescription = request.FileDescription
                };

                // 이미지 업로드를 위해 리포지토리 사용
                await imageRepository.Uploade(imageDomainModel);

                return Ok(imageDomainModel); // 업로드된 이미지 정보 반환
            }

            return BadRequest(ModelState); // 유효성 검사 실패 시 오류 반환
        }

        // 파일 업로드 유효성 검사 메서드
        private void ValidateFileUpload(ImageUploadRequestDto request)
        {
            var allowedExtensions = new string[] { ".jpg", ".jpeg", ".Png" }; // 허용되는 확장자 목록

            // 파일 확장자 검사
            if (!allowedExtensions.Contains(Path.GetExtension(request.File.FileName)))
            {
                ModelState.AddModelError("file", "Unsupported file extension"); // 지원되지 않는 파일 확장자 오류 추가
            }

            // 파일 크기 검사 (10MB 초과 여부)
            if (request.File.Length > 10485760) // 10MB
            {
                ModelState.AddModelError("file", "File Size more than 10MB, Please upload a smaller size file"); // 파일 크기 초과 오류 추가
            }
        }
    }
}

ImageUploadRequestDto.cs

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
using System.ComponentModel.DataAnnotations;
namespace NZWalks.API.Models.DTO
{
public class ImageUploadRequestDto
{
[Required]
public IFormFile File { get; set; }
[Required]
public string Filename { get; set; }
public string? FileDescription { get; set; }
}
}
using System.ComponentModel.DataAnnotations; namespace NZWalks.API.Models.DTO { public class ImageUploadRequestDto { [Required] public IFormFile File { get; set; } [Required] public string Filename { get; set; } public string? FileDescription { get; set; } } }
using System.ComponentModel.DataAnnotations;

namespace NZWalks.API.Models.DTO
{
    public class ImageUploadRequestDto
    {
        [Required]
        public IFormFile File { get; set; }
        
        [Required]
        public string Filename { get; set; }

        public string? FileDescription { get; set; }

    }
}

IImageRepository.cs

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
using NZWalks.API.Models.Domain;
namespace NZWalks.API.Repositories
{
public interface IImageRepository
{
Task<Image> Uploade(Image image);
}
}
using NZWalks.API.Models.Domain; namespace NZWalks.API.Repositories { public interface IImageRepository { Task<Image> Uploade(Image image); } }
using NZWalks.API.Models.Domain;

namespace NZWalks.API.Repositories
{
    public interface IImageRepository
    {
        Task<Image> Uploade(Image image);
    }
}

LocalImageRepository.cs

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
using NZWalks.API.Data; // 데이터 컨텍스트를 사용하기 위한 네임스페이스
using NZWalks.API.Models.Domain; // 도메인 모델을 사용하기 위한 네임스페이스
namespace NZWalks.API.Repositories
{
public class LocalImageRepository : IImageRepository
{
private readonly IWebHostEnvironment webHostEnvironment;
private readonly IHttpContextAccessor httpContextAccessor;
private readonly NZWalksDbcontext dbcontext;
// LocalImageRepository 생성자
// 필요한 종속성들(IWebHostEnvironment, IHttpContextAccessor, NZWalksDbcontext)을 주입받아 초기화
public LocalImageRepository(IWebHostEnvironment webHostEnvironment, IHttpContextAccessor httpContextAccessor, NZWalksDbcontext dbcontext)
{
this.webHostEnvironment = webHostEnvironment;
this.httpContextAccessor = httpContextAccessor;
this.dbcontext = dbcontext;
}
// 이미지 업로드 메서드
public async Task<Image> Uploade(Image image)
{
// 로컬 파일 경로 생성
var localFilePath = Path.Combine(webHostEnvironment.ContentRootPath, "Images", $"{Path.GetFileNameWithoutExtension(image.Filename)}{image.FileExtension}");
// 로컬 경로에 이미지 업로드
using var stream = new FileStream(localFilePath, FileMode.Create);
await image.File.CopyToAsync(stream);
// URL 경로 생성
var urlFilePath = $"{httpContextAccessor.HttpContext.Request.Scheme}://{httpContextAccessor.HttpContext.Request.Host}{httpContextAccessor.HttpContext.Request.PathBase}/Images/{Path.GetFileNameWithoutExtension(image.Filename)}{image.FileExtension}";
image.FilePath = urlFilePath;
// 이미지 정보를 Images 테이블에 추가
await dbcontext.Images.AddAsync(image);
await dbcontext.SaveChangesAsync();
return image; // 업로드된 이미지 반환
}
}
}
using NZWalks.API.Data; // 데이터 컨텍스트를 사용하기 위한 네임스페이스 using NZWalks.API.Models.Domain; // 도메인 모델을 사용하기 위한 네임스페이스 namespace NZWalks.API.Repositories { public class LocalImageRepository : IImageRepository { private readonly IWebHostEnvironment webHostEnvironment; private readonly IHttpContextAccessor httpContextAccessor; private readonly NZWalksDbcontext dbcontext; // LocalImageRepository 생성자 // 필요한 종속성들(IWebHostEnvironment, IHttpContextAccessor, NZWalksDbcontext)을 주입받아 초기화 public LocalImageRepository(IWebHostEnvironment webHostEnvironment, IHttpContextAccessor httpContextAccessor, NZWalksDbcontext dbcontext) { this.webHostEnvironment = webHostEnvironment; this.httpContextAccessor = httpContextAccessor; this.dbcontext = dbcontext; } // 이미지 업로드 메서드 public async Task<Image> Uploade(Image image) { // 로컬 파일 경로 생성 var localFilePath = Path.Combine(webHostEnvironment.ContentRootPath, "Images", $"{Path.GetFileNameWithoutExtension(image.Filename)}{image.FileExtension}"); // 로컬 경로에 이미지 업로드 using var stream = new FileStream(localFilePath, FileMode.Create); await image.File.CopyToAsync(stream); // URL 경로 생성 var urlFilePath = $"{httpContextAccessor.HttpContext.Request.Scheme}://{httpContextAccessor.HttpContext.Request.Host}{httpContextAccessor.HttpContext.Request.PathBase}/Images/{Path.GetFileNameWithoutExtension(image.Filename)}{image.FileExtension}"; image.FilePath = urlFilePath; // 이미지 정보를 Images 테이블에 추가 await dbcontext.Images.AddAsync(image); await dbcontext.SaveChangesAsync(); return image; // 업로드된 이미지 반환 } } }
using NZWalks.API.Data; // 데이터 컨텍스트를 사용하기 위한 네임스페이스
using NZWalks.API.Models.Domain; // 도메인 모델을 사용하기 위한 네임스페이스

namespace NZWalks.API.Repositories
{
    public class LocalImageRepository : IImageRepository
    {
        private readonly IWebHostEnvironment webHostEnvironment;
        private readonly IHttpContextAccessor httpContextAccessor;
        private readonly NZWalksDbcontext dbcontext;

        // LocalImageRepository 생성자
        // 필요한 종속성들(IWebHostEnvironment, IHttpContextAccessor, NZWalksDbcontext)을 주입받아 초기화
        public LocalImageRepository(IWebHostEnvironment webHostEnvironment, IHttpContextAccessor httpContextAccessor, NZWalksDbcontext dbcontext)
        {
            this.webHostEnvironment = webHostEnvironment;
            this.httpContextAccessor = httpContextAccessor;
            this.dbcontext = dbcontext;
        }

        // 이미지 업로드 메서드
        public async Task<Image> Uploade(Image image)
        {
            // 로컬 파일 경로 생성
            var localFilePath = Path.Combine(webHostEnvironment.ContentRootPath, "Images", $"{Path.GetFileNameWithoutExtension(image.Filename)}{image.FileExtension}");

            // 로컬 경로에 이미지 업로드
            using var stream = new FileStream(localFilePath, FileMode.Create);
            await image.File.CopyToAsync(stream);

            // URL 경로 생성
            var urlFilePath = $"{httpContextAccessor.HttpContext.Request.Scheme}://{httpContextAccessor.HttpContext.Request.Host}{httpContextAccessor.HttpContext.Request.PathBase}/Images/{Path.GetFileNameWithoutExtension(image.Filename)}{image.FileExtension}";
            image.FilePath = urlFilePath;

            // 이미지 정보를 Images 테이블에 추가
            await dbcontext.Images.AddAsync(image);
            await dbcontext.SaveChangesAsync();

            return image; // 업로드된 이미지 반환
        }
    }
}

Program.cs 변경

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore; // Entity Framework Core 기능을 사용하기 위한 네임스페이스
using Microsoft.Extensions.FileProviders;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using NZWalks.API.Data;
using NZWalks.API.Mappings;
using NZWalks.API.Models.Domain;
using NZWalks.API.Repositories;
using System.Text; // 데이터 컨텍스트를 사용하기 위한 네임스페이스
var builder = WebApplication.CreateBuilder(args); // 웹 애플리케이션 빌더 객체 생성
// Add services to the container.
builder.Services.AddControllers(); // 컨트롤러 서비스를 추가하여 MVC 패턴을 지원
builder.Services.AddHttpContextAccessor(); // HttpContextAccessor를 서비스 컨테이너에 추가
// Swagger/OpenAPI 설정에 대한 더 많은 정보를 얻으려면 https://aka.ms/aspnetcore/swashbuckle 참고
builder.Services.AddEndpointsApiExplorer(); // API 탐색기를 추가하여 API 문서를 자동 생성
// Swagger 생성을 위한 서비스 추가
builder.Services.AddSwaggerGen(options => {
// 제목과 버전을 정의하여 Swagger 문서 설정
options.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo {
Title = "NZ Walks API",
Version = "v1"
});
// JWT Bearer 보안 정의 추가
options.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme,
new Microsoft.OpenApi.Models.OpenApiSecurityScheme()
{
Name = "Authorization", // 인증 헤더 이름
In = ParameterLocation.Header, // 인증 정보의 위치 (헤더)
Type = SecuritySchemeType.ApiKey, // 인증 유형 (API 키)
Scheme = JwtBearerDefaults.AuthenticationScheme // 스키마 설정
}
);
// 정의된 보안 스키마를 사용한 보안 요구 사항 추가
options.AddSecurityRequirement(new OpenApiSecurityRequirement {
{
new OpenApiSecurityScheme {
Reference = new OpenApiReference {
Type = ReferenceType.SecurityScheme, // 참조 유형 설정
Id = JwtBearerDefaults.AuthenticationScheme // 참조 ID 설정
},
Scheme = "Oauth2", // 스키마 설정
Name = JwtBearerDefaults.AuthenticationScheme, // 스키마 이름
In = ParameterLocation.Header // 위치 설정
},
new List<string>()
}
});
});
// DbContext 서비스를 추가하여 SQL Server를 사용하도록 설정
builder.Services.AddDbContext<NZWalksDbcontext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("NZWalksConnectionString"))
);
// DbContext 서비스를 추가하여 SQL Server를 사용하도록 설정
builder.Services.AddDbContext<NZWalksAuthDbcontext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("NZWalksAuthConnectionString"))
);
builder.Services.AddScoped<IRegionRepository, SQLRegionRepository>(); // Main DB Region
builder.Services.AddScoped<IWalkRepository, SQLWalkRepository>(); // Main DB Walk
builder.Services.AddScoped<ITokenRepository, TokenRepository>(); // Token - Controller에서 사용 가능
builder.Services.AddScoped<IImageRepository, LocalImageRepository>(); // Image DB
// builder.Services.AddScoped<IRegionRepository, InMemoryRegionRepository>(); // Test DB (In Memory)
builder.Services.AddAutoMapper(typeof(AutoMapperProfiles)); // AutoMapper 프로필 추가
// Identity Core 서비스를 추가하여 IdentityUser를 사용하도록 설정
builder.Services.AddIdentityCore<IdentityUser>()
// IdentityRole을 추가하여 역할 관리를 지원
.AddRoles<IdentityRole>()
// 데이터 보호 토큰 제공자를 추가하여 "NZWalks"라는 이름의 토큰 제공자 설정
.AddTokenProvider<DataProtectorTokenProvider<IdentityUser>>("NZWalks")
// Entity Framework 스토어를 사용하여 NZWalksAuthDbcontext를 통한 저장소 관리
.AddEntityFrameworkStores<NZWalksAuthDbcontext>()
// 기본 토큰 제공자 추가
.AddDefaultTokenProviders();
// Identity 옵션을 구성하여 비밀번호 정책 설정
builder.Services.Configure<IdentityOptions>(options =>{
options.Password.RequireDigit = false; // 비밀번호에 숫자 필요 없음
options.Password.RequireLowercase = false; // 비밀번호에 소문자 필요 없음
options.Password.RequireNonAlphanumeric = false; // 비밀번호에 알파벳 이외의 문자 필요 없음
options.Password.RequireUppercase = false; // 비밀번호에 대문자 필요 없음
options.Password.RequiredLength = 6; // 비밀번호 최소 길이 6자
options.Password.RequiredUniqueChars = 1; // 비밀번호에 최소 1개의 고유 문자 필요
});
// JWT 인증 설정 추가
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) // JWT Bearer 인증 스키마 사용
.AddJwtBearer(options => // JWT Bearer 인증 설정
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidateIssuer = true, // 발행자(issuer) 유효성 검사 활성화
ValidateAudience = true, // 수신자(audience) 유효성 검사 활성화
ValidateLifetime = true, // 토큰의 유효 기간 검사 활성화
ValidateIssuerSigningKey = true, // 서명 키 유효성 검사 활성화
ValidIssuer = builder.Configuration["Jwt:Issuer"], // 유효한 발행자 설정
ValidAudience = builder.Configuration["Jwt:Audience"], // 유효한 수신자 설정
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])) // 서명 키 설정
});
var app = builder.Build(); // 애플리케이션 빌드
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment()){
// 개발 환경에서만 Swagger를 사용하도록 설정
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection(); // HTTP 요청을 HTTPS로 리디렉션
app.UseAuthentication(); // JWT 인증 미들웨어 추가
// 이 코드는 JWT 인증을 처리하여 사용자 요청을 검증함
// 정적 파일 제공을 위한 미들웨어 설정
app.UseStaticFiles(new StaticFileOptions {
FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "Images")),
RequestPath = "/Images"
});
app.UseAuthorization(); // 권한 부여 미들웨어 사용
// 인증된 사용자의 권한을 검증함
app.MapControllers(); // 컨트롤러에 대한 요청을 매핑
app.Run(); // 애플리케이션 실행
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; // Entity Framework Core 기능을 사용하기 위한 네임스페이스 using Microsoft.Extensions.FileProviders; using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi.Models; using NZWalks.API.Data; using NZWalks.API.Mappings; using NZWalks.API.Models.Domain; using NZWalks.API.Repositories; using System.Text; // 데이터 컨텍스트를 사용하기 위한 네임스페이스 var builder = WebApplication.CreateBuilder(args); // 웹 애플리케이션 빌더 객체 생성 // Add services to the container. builder.Services.AddControllers(); // 컨트롤러 서비스를 추가하여 MVC 패턴을 지원 builder.Services.AddHttpContextAccessor(); // HttpContextAccessor를 서비스 컨테이너에 추가 // Swagger/OpenAPI 설정에 대한 더 많은 정보를 얻으려면 https://aka.ms/aspnetcore/swashbuckle 참고 builder.Services.AddEndpointsApiExplorer(); // API 탐색기를 추가하여 API 문서를 자동 생성 // Swagger 생성을 위한 서비스 추가 builder.Services.AddSwaggerGen(options => { // 제목과 버전을 정의하여 Swagger 문서 설정 options.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo { Title = "NZ Walks API", Version = "v1" }); // JWT Bearer 보안 정의 추가 options.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme, new Microsoft.OpenApi.Models.OpenApiSecurityScheme() { Name = "Authorization", // 인증 헤더 이름 In = ParameterLocation.Header, // 인증 정보의 위치 (헤더) Type = SecuritySchemeType.ApiKey, // 인증 유형 (API 키) Scheme = JwtBearerDefaults.AuthenticationScheme // 스키마 설정 } ); // 정의된 보안 스키마를 사용한 보안 요구 사항 추가 options.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, // 참조 유형 설정 Id = JwtBearerDefaults.AuthenticationScheme // 참조 ID 설정 }, Scheme = "Oauth2", // 스키마 설정 Name = JwtBearerDefaults.AuthenticationScheme, // 스키마 이름 In = ParameterLocation.Header // 위치 설정 }, new List<string>() } }); }); // DbContext 서비스를 추가하여 SQL Server를 사용하도록 설정 builder.Services.AddDbContext<NZWalksDbcontext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("NZWalksConnectionString")) ); // DbContext 서비스를 추가하여 SQL Server를 사용하도록 설정 builder.Services.AddDbContext<NZWalksAuthDbcontext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("NZWalksAuthConnectionString")) ); builder.Services.AddScoped<IRegionRepository, SQLRegionRepository>(); // Main DB Region builder.Services.AddScoped<IWalkRepository, SQLWalkRepository>(); // Main DB Walk builder.Services.AddScoped<ITokenRepository, TokenRepository>(); // Token - Controller에서 사용 가능 builder.Services.AddScoped<IImageRepository, LocalImageRepository>(); // Image DB // builder.Services.AddScoped<IRegionRepository, InMemoryRegionRepository>(); // Test DB (In Memory) builder.Services.AddAutoMapper(typeof(AutoMapperProfiles)); // AutoMapper 프로필 추가 // Identity Core 서비스를 추가하여 IdentityUser를 사용하도록 설정 builder.Services.AddIdentityCore<IdentityUser>() // IdentityRole을 추가하여 역할 관리를 지원 .AddRoles<IdentityRole>() // 데이터 보호 토큰 제공자를 추가하여 "NZWalks"라는 이름의 토큰 제공자 설정 .AddTokenProvider<DataProtectorTokenProvider<IdentityUser>>("NZWalks") // Entity Framework 스토어를 사용하여 NZWalksAuthDbcontext를 통한 저장소 관리 .AddEntityFrameworkStores<NZWalksAuthDbcontext>() // 기본 토큰 제공자 추가 .AddDefaultTokenProviders(); // Identity 옵션을 구성하여 비밀번호 정책 설정 builder.Services.Configure<IdentityOptions>(options =>{ options.Password.RequireDigit = false; // 비밀번호에 숫자 필요 없음 options.Password.RequireLowercase = false; // 비밀번호에 소문자 필요 없음 options.Password.RequireNonAlphanumeric = false; // 비밀번호에 알파벳 이외의 문자 필요 없음 options.Password.RequireUppercase = false; // 비밀번호에 대문자 필요 없음 options.Password.RequiredLength = 6; // 비밀번호 최소 길이 6자 options.Password.RequiredUniqueChars = 1; // 비밀번호에 최소 1개의 고유 문자 필요 }); // JWT 인증 설정 추가 builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) // JWT Bearer 인증 스키마 사용 .AddJwtBearer(options => // JWT Bearer 인증 설정 options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters { ValidateIssuer = true, // 발행자(issuer) 유효성 검사 활성화 ValidateAudience = true, // 수신자(audience) 유효성 검사 활성화 ValidateLifetime = true, // 토큰의 유효 기간 검사 활성화 ValidateIssuerSigningKey = true, // 서명 키 유효성 검사 활성화 ValidIssuer = builder.Configuration["Jwt:Issuer"], // 유효한 발행자 설정 ValidAudience = builder.Configuration["Jwt:Audience"], // 유효한 수신자 설정 IssuerSigningKey = new SymmetricSecurityKey( Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])) // 서명 키 설정 }); var app = builder.Build(); // 애플리케이션 빌드 // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()){ // 개발 환경에서만 Swagger를 사용하도록 설정 app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); // HTTP 요청을 HTTPS로 리디렉션 app.UseAuthentication(); // JWT 인증 미들웨어 추가 // 이 코드는 JWT 인증을 처리하여 사용자 요청을 검증함 // 정적 파일 제공을 위한 미들웨어 설정 app.UseStaticFiles(new StaticFileOptions { FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "Images")), RequestPath = "/Images" }); app.UseAuthorization(); // 권한 부여 미들웨어 사용 // 인증된 사용자의 권한을 검증함 app.MapControllers(); // 컨트롤러에 대한 요청을 매핑 app.Run(); // 애플리케이션 실행
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore; // Entity Framework Core 기능을 사용하기 위한 네임스페이스
using Microsoft.Extensions.FileProviders;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using NZWalks.API.Data;
using NZWalks.API.Mappings;
using NZWalks.API.Models.Domain;
using NZWalks.API.Repositories;
using System.Text; // 데이터 컨텍스트를 사용하기 위한 네임스페이스

var builder = WebApplication.CreateBuilder(args); // 웹 애플리케이션 빌더 객체 생성

// Add services to the container.
builder.Services.AddControllers(); // 컨트롤러 서비스를 추가하여 MVC 패턴을 지원

builder.Services.AddHttpContextAccessor(); // HttpContextAccessor를 서비스 컨테이너에 추가

// Swagger/OpenAPI 설정에 대한 더 많은 정보를 얻으려면 https://aka.ms/aspnetcore/swashbuckle 참고
builder.Services.AddEndpointsApiExplorer(); // API 탐색기를 추가하여 API 문서를 자동 생성

// Swagger 생성을 위한 서비스 추가
builder.Services.AddSwaggerGen(options => {    
    // 제목과 버전을 정의하여 Swagger 문서 설정
    options.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo    {        
        Title = "NZ Walks API",        
        Version = "v1"    
    });    
    // JWT Bearer 보안 정의 추가
    options.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme,        
        new Microsoft.OpenApi.Models.OpenApiSecurityScheme()        
        {            
            Name = "Authorization",  // 인증 헤더 이름                    
            In = ParameterLocation.Header,  // 인증 정보의 위치 (헤더)                    
            Type = SecuritySchemeType.ApiKey,  // 인증 유형 (API 키)                    
            Scheme = JwtBearerDefaults.AuthenticationScheme  // 스키마 설정        
        }    
    );    
    // 정의된 보안 스키마를 사용한 보안 요구 사항 추가
    options.AddSecurityRequirement(new OpenApiSecurityRequirement {        
        {            
            new OpenApiSecurityScheme {                
                Reference = new OpenApiReference {                    
                    Type = ReferenceType.SecurityScheme,  // 참조 유형 설정                    
                    Id = JwtBearerDefaults.AuthenticationScheme  // 참조 ID 설정                
                },                
                Scheme = "Oauth2",  // 스키마 설정                
                Name = JwtBearerDefaults.AuthenticationScheme,  // 스키마 이름                
                In = ParameterLocation.Header  // 위치 설정            
            },            
            new List<string>()        
        }    
    });
});

// DbContext 서비스를 추가하여 SQL Server를 사용하도록 설정
builder.Services.AddDbContext<NZWalksDbcontext>(options =>    
    options.UseSqlServer(builder.Configuration.GetConnectionString("NZWalksConnectionString"))
);

// DbContext 서비스를 추가하여 SQL Server를 사용하도록 설정
builder.Services.AddDbContext<NZWalksAuthDbcontext>(options =>    
    options.UseSqlServer(builder.Configuration.GetConnectionString("NZWalksAuthConnectionString"))
);

builder.Services.AddScoped<IRegionRepository, SQLRegionRepository>(); // Main DB Region
builder.Services.AddScoped<IWalkRepository, SQLWalkRepository>(); // Main DB Walk
builder.Services.AddScoped<ITokenRepository, TokenRepository>(); // Token - Controller에서 사용 가능
builder.Services.AddScoped<IImageRepository, LocalImageRepository>(); // Image DB
// builder.Services.AddScoped<IRegionRepository, InMemoryRegionRepository>(); // Test DB (In Memory)

builder.Services.AddAutoMapper(typeof(AutoMapperProfiles)); // AutoMapper 프로필 추가

// Identity Core 서비스를 추가하여 IdentityUser를 사용하도록 설정
builder.Services.AddIdentityCore<IdentityUser>()    
    // IdentityRole을 추가하여 역할 관리를 지원
    .AddRoles<IdentityRole>()    
    // 데이터 보호 토큰 제공자를 추가하여 "NZWalks"라는 이름의 토큰 제공자 설정
    .AddTokenProvider<DataProtectorTokenProvider<IdentityUser>>("NZWalks")    
    // Entity Framework 스토어를 사용하여 NZWalksAuthDbcontext를 통한 저장소 관리
    .AddEntityFrameworkStores<NZWalksAuthDbcontext>()    
    // 기본 토큰 제공자 추가
    .AddDefaultTokenProviders();

// Identity 옵션을 구성하여 비밀번호 정책 설정
builder.Services.Configure<IdentityOptions>(options =>{    
    options.Password.RequireDigit = false; // 비밀번호에 숫자 필요 없음    
    options.Password.RequireLowercase = false; // 비밀번호에 소문자 필요 없음    
    options.Password.RequireNonAlphanumeric = false; // 비밀번호에 알파벳 이외의 문자 필요 없음    
    options.Password.RequireUppercase = false; // 비밀번호에 대문자 필요 없음    
    options.Password.RequiredLength = 6; // 비밀번호 최소 길이 6자    
    options.Password.RequiredUniqueChars = 1; // 비밀번호에 최소 1개의 고유 문자 필요
});

// JWT 인증 설정 추가
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) // JWT Bearer 인증 스키마 사용    
    .AddJwtBearer(options => // JWT Bearer 인증 설정    
    options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters    
    {        
        ValidateIssuer = true, // 발행자(issuer) 유효성 검사 활성화        
        ValidateAudience = true, // 수신자(audience) 유효성 검사 활성화        
        ValidateLifetime = true, // 토큰의 유효 기간 검사 활성화        
        ValidateIssuerSigningKey = true, // 서명 키 유효성 검사 활성화        
        ValidIssuer = builder.Configuration["Jwt:Issuer"], // 유효한 발행자 설정        
        ValidAudience = builder.Configuration["Jwt:Audience"], // 유효한 수신자 설정        
        IssuerSigningKey = new SymmetricSecurityKey(            
            Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])) // 서명 키 설정    
    });

var app = builder.Build(); // 애플리케이션 빌드

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment()){    
    // 개발 환경에서만 Swagger를 사용하도록 설정    
    app.UseSwagger();    
    app.UseSwaggerUI();
}

app.UseHttpsRedirection(); // HTTP 요청을 HTTPS로 리디렉션

app.UseAuthentication(); // JWT 인증 미들웨어 추가
// 이 코드는 JWT 인증을 처리하여 사용자 요청을 검증함

// 정적 파일 제공을 위한 미들웨어 설정
app.UseStaticFiles(new StaticFileOptions {     
    FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "Images")),
    RequestPath = "/Images"
});

app.UseAuthorization(); // 권한 부여 미들웨어 사용
// 인증된 사용자의 권한을 검증함

app.MapControllers(); // 컨트롤러에 대한 요청을 매핑

app.Run(); // 애플리케이션 실행
정적 파일

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다