본문 바로가기
Dotnet/.NET , ASP.NET CORE

최소 api에 jwt bearer 인증 적용하고 Swagger 설정까지

by 잘먹는 개발자 에단 2024. 8. 1.

*** 들어가기 전에 이것저것 살펴보기

 

* 여러 포트에서 동작하게 할 수 있다.

app.Urls.Add("http://localhost:3000")
app.Urls.Add("http://localhost:4000")

app.Run();

 

 

* 환경변수에서 포트번호를 읽어와서 설정할 수도 있다.

var app = WebApplication.Create(args);
var port = Environment.GetEnvironmentVariable("PORT") ?? "3000";

app.MapGet("/", () => "Hello world");

app.Run($"http://localhost:{port}");

 

 

* 로그온 어플리케이션 시작에 메시지를 쓸 수 있다.

var app = WebApplication.Create(args);
app.Logger.LogInformation("The app started");
app.MapGet("/", () => {return "Hello world"});
app.Run();

 

 

* 서비스 추가는 다음과 같다. 

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddMemoryCache();
builder.Services.AddScoped<ITodoRepository, TodoRepository>();
var app = builder.Build();

 

 

* 미들웨어를 추가할 수 있다.

var app = WebApplication.Create(args);
app.UseFileServer();

app.MapGet("/", () => "Hello world");

app.Run();

 

 

* 예외페이지를 다음과 같이 설정할 수 있다.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => {
		throw new InvalidOperationException("Oops, the '/' route has thrown an exception.");   
	});

app.Run();

그럼 이런 예외 페이지를 띄우게 된다. 

 

 

* 페이로드를 받아서 무언가를 처리할때

1. 모델을 선언한다.

2. 해당 모델을 인자에다가 받는다고 넣어놓는다.

app.MapGet("/todos", async (TodoDb db) => 
    await db.Todos.ToListAsync());

 

 

** 최소 api는 인증, 권한부여, 로깅등의 기능 구현이 상대적으로 쉽다. 

성능도 전통적인 MVC 패턴의 api들보다 빠르다. 

 

 

** HttpPost 메서드의 가장 이상적인 반환값은 200 OK가 아니라 201 Created다. 

Results.Created(), TypedResults.Created()는 201 응답코드를 반환한다. 

 

* 라우트 파라미터를 다음과 같이 받아서 사용할 수 있다.

app.MapGet("/todos/{id}", async Task<Results<Ok<Todo>, NotFound>> (int id, TodoDb db) => 
    await db.Todos.FindAsync(id)
        is Todo todo 
            ? TypedResults.Ok(todo)
            : TypedResults.NotFound());

 

 

 

 

* 파라미터 바인딩

- 쿼리 문자열 바인딩 : URL의 쿼리 문자열을 메서드의 매개변수로 바인딩

- 경로 변수 바인딩 : url 경로의 일부분을 매개변수로 바인딩

- 요청 본문 바인딩 : http 요청 본문의 데이터를 매개변수로 바인딩한다. 

 

***** 방법은 다음과 같다. 

* 쿼리 문자열 바인딩

app.MapGet("/search", (string query) => $"검색어 : {query}";

 

* 경로 변수 바인딩

app.MapGet("/items/{id}", (int id) => "아이템 Id :{id});

- URL 경로의 {id} 부분을 int타입의 id 매개변수로 바인딩한다.

 

* 요청 본문 바인딩

app.MapPost("/items", (Item item) => {
    // Item 객체 처리
});

json데이터를 모델(Item)의 클래스로 인스턴스로 바인딩한다.

 

 

 

 

*** 최소 api (minimal api)에서 반복되는 url은 그룹으로 묶어서 관리할 수 있다. from dotnet 7 ~ )

- 닷넷 7에서 새롭게 도입된 기능

- 엔드포인트를 그룹화할 수 있도록 MapGroup() 확장 메서드를 제공한다.

// MapGroup() 메서드에 URL 접두사를 지정하고 같은 API들을 묶어주면 된다.
var todos = app.MapGroup("/todos");

// 여기에서
app.MapGet("/todos/{id}", async(TodoDb db) => 
	await db.Todos.ToListAsync());

// 위에서 app을 todo로 바꾼다.
todos.MapGet("/{id}", async(TodoDb db) => 
	await db.Todos.ToListAsync());


그러면 이제 엔드포인트는 /todos/{id}가 된다.

 

 

* 스웨거를 사용하기 위해서 필요한 Nuget 패키지는

- Microsoft.OpenApi 혹은 Microsoft.OpenApi.Models

- Swashbuckle.AspNetCore

 

 

 

*** 최소 api에 인증기능을 추가할 수 있다.

var todos = app.MapGroup("/todos").RequireAuthorization();

- 아까 만들었던 todos에다가 RequireAuthorization을 추가한다.

- 이 경우에 jwt token을 가지고 있지 않으면, api 호출을 할 수 없다.

- 인증되지 않은 상태로 api에 접근을 시도하면 401 에러 메시지가 상태값으로 반환된다. 

 

 

*** jwt

- json web token

- 웹 표준 rfc7519

- 두 당사자 사이에서 정보를 안전하게 전송하기 위한 방법 제공

- 디지털 서명이 가능하기 때문에, 정보가 검증되고 신뢰할 수 있는지 확인할 수 있고, 송신자가 정말로 클레임한 대로 해당 정보를 보낸 것인지 검증할 수 있다. 

- 이 토큰은 자체적으로 필요한 모든 정보를 가지고 있다.

    ㄴ 중앙 인증 서버를 통하지 않고도 통신하는 양 당사자 간에 인증과 정보 교환을 진행할 수 있다.

    ㄴ 주로 인증 및 정보 교환의 목적으로 사용되고

    ㄴ 특히 단일 로그인 SSO에서 많이 사용됨

 

 

*** dotnet user-jwts create

- JWT 인증을 사용하기 위해서는 토큰 발행 절차가 필요하다. 

 

- Bearer 토큰을 생성한다. 

dotnet user-jwts create --project 프로젝트명

 

- 그 다음, 진입점에 추가한다.

builder.Services.AddAuthentication().AddJwtBearer(); // 인증 
builder.Services.AddAuthorization(); // 권한

 

- 이후에 서비스를 적용한다.

app.UseAuthorization(); // 권한

 

 

- 이후에 적용할 api 엔드포인트 설정 뒤에다가 .RequireAuthorization()을 적용하면 

app.MapGet("/", () => "Started..!").RequireAuthorization();

 

 

인증된 사용자만 해당 api를 콜할 권한을 가지게 된다. 

인증되지 않은 사용자가 api를 콜하면 401 에러메시지를 받는다. 

 

 

 

 

근데, 처음에 Swagger 문서를 생성하면 저기 보이는 Authorize 버튼이 없다.

저 버튼을 통해서 Bearer 토큰을 변경할 수 있다.

 

 

*** Swagger 문서에 Authorize 기능 추가하려면

builder.Services.AddSwaggerGen(options =>
        {
            
            options.SwaggerDoc("v1", new OpenApiInfo
            {
                Version = "v1",
                Title = "TEST API",
                Description = "An API to get TestData"
            });
            
            //추가
            options.InferSecuritySchemes();
            options.AddSecurityRequirement(new Microsoft.OpenApi.Models.OpenApiSecurityRequirement 
            {
                { 
                    new OpenApiSecurityScheme
                    {
                        Reference = new OpenApiReference 
                        { 
                           Type = ReferenceType.SecurityScheme, Id = "Bearer"  
                        }
                    },
                    new string[] { }
                }
            });
            // 추가 끝
        });
        
        // 추가
        builder.Services.Configure<SwaggerGeneratorOptions>(options =>
        {
            options.InferSecuritySchemes = true;
        });
        // 추가 끝

 

- 저 두 코드를 추가하면 된다.

 

 

 

*** 궁금한 점들이 생겨서!

#1. 만약에 토큰을 중간에 다시 생성하면 이전에 쓰던 토큰들은 어떻게 되나?

- 새로운 토큰을 생성하면 이전에 사용되던 토큰의 유효성에 대한 처리방식은 !여러가지!가 있다.

 

1. 토큰 만료시간 설정

- JWT 토큰은 만료시간( exp 클레임 )을 가지고 있다.

- 새로운 토큰이 생성되면, 이전 토큰은 일정 시간이 지나면 자동으로 만료되고

- 따라서 클라이언트는 새로운 토큰을 사용하도록 유도된다.

 

2. 블랙리스트 사용

- 서버에서 이전 토큰을 블랙리스트에 추가하는 방법이 있다. 

- 블랙리스트는 일반적으로 데이터베이스나 인메모리 저장소에 저장되며, 각 요청 시 토큰이 블랙리스트에 있는지 확인한다. 

- 이 방법은 구현이 복잡하고 성능에 영향을 미칠 수 있다. 

 

3. 토큰의 REFRESH 토큰 사용

- JWT와 함께 REFRESH 토큰을 사용하는 방법도 있다.

- 리프레시 토큰은 주기적으로 새로운 액세스 토큰을 발급받기 위해서 사용되는데, 새로운 액세스 토큰이 발급되면, 이전 액세스 토큰은 더이상 유효하지 않다. 

- 서버에서 리프레시 토큰을 검증하고 새로운 액세스 토큰을 발급한다.

 

4. 토큰의 버전 관리

- 토큰에 버전 정보를 포함시켜, 서버에서 현재 유효한 토큰 버전을 관리한다.

- 새로운 토큰을 생성할 때 버전을 증가시키고, 서버는 현재 유효한 버전의 토큰만을 허용하도록 한다. 

 

 

* 출처 

https://www.dotnetnote.com/docs/aspnetcore/aspnetcore-todo-list-with-minimal-apis/

 

ASP.NET Core 8.0 CRUD API 만들기

TODO 리스트 CRUD Web API 만들기 with .NET 8 Minimal APIs 추천 자료: .NET Blazor에 대해 알아보시겠어요? .NET Blazor 알아보기를 확인해보세요! 이번 강의에서는 ASP.NET Core 8.0의 최소 API(Minimal APIs)를 사용하여 T

www.dotnetnote.com

 

'Dotnet > .NET , ASP.NET CORE' 카테고리의 다른 글

C#에서의 http 요청/응답/사용  (0) 2024.11.19