C# 사용자 Middleware 를 이용한 WebAPI Authentication

Custom Middleware 를 이용한 WebAPI 인증(Authentication)

ㆍ사용자 Middleware 작성하기

next(RequestDelegate) , Invoke(InvokeAsync) ,  await next(context)

 1) 생성자를 통해 next  객체 주입받고 , 처리 완료 후 next(context) 마지막에 호출 (RequestDeletegate next )
 2) Invoke 또는 InvokeAsync  메서드 만들기  public async Task InvokeAsync(HttpContext context) {    }
     없으면 예외발생, InvalidOperationException: No public ‘Invoke’ or ‘InvokeAsync’ method found for middleware of type 
 3)  startup.cs 에 미들웨어 등록하기 app.UseMiddleware<MYMIDDLEWARE>();  이때 invoke 또는 invokeAsync 를 찾음

ㆍ 미들웨어 기본구조 & 미들웨어 등록

ㆍ 사용자 미들웨어 기본 구성
public class MyMiddleware
 {
          private readOnly RequestDelegate _next;
          
           // 생산자를 통한 의존성 주입
           public MyMiddleware(RequestDelegate next)    
           {
                  this._next = next
           }

           // app.UseMiddleware() 로  호출시 Invoke 또는 InvokeAsync 함수를 찾는다.
           // 함수가 없으며,  InvalidOperationException 예외발생 

           public Async Task InvokeAsync(HttpContext context)             
          {
                 // 처리          
                await this._next(context);
           }
  }

ㆍ 미들웨어 startup.cs 등록
     app.UseMiddleware<MyMiddleware>();
     app.UseRouting();
     app.UseAuthentication();

MyAPIAuthMiddleware.cs
———————————————————————————————————————————————————-
public class MyAPIAuthMiddleware
{
          private const string KeyName = “APIKEY”;
          private readonly RequestDelegate _next;
          private readOnly IConfiguration _configuration;

           public MyAPIAuthMiddleware(RequestDelegate next , IConfiguration configuration)
           {
                  this._next = next;
                  this._configuration = configuration;
           }
          
           public async Task InvokeAsync(HttpContext contenxt)
           {
                 string serverKeyFromDI ;
                 string serverKeyFromService ;

                 string clientKey;

                 // 요청헤더로부터 클라이언트가 , true or false 그리고 key 값은  outAPIKey 에 할당
                 if (!context.Request.Headers.TryGetValue(KeyName , out val outAPIKey))
                 {
                        await  context.Response.WriteyAsync(“client API key empty”);
                        return;
                 }

                  clientKey = outAPIKey.toString().Trim();

               // 1) 생성사 의존성 주입으로 받은 IConfiguration 으로 가져오기
                   string serverKeyFromDI = configuration[“API:Key”].toString();

               // 2) DI 로 등록된 객체 RequestService.GetRequiredService<T> 로 IConfiguration 불러오기
                   var appSetting = context.RequestService.GetRequiredService<IConfiguration>();
                   string serverKeyFromService = appSetting.getValue<string>(“API:Key”);

                   if (clientKey != serverKeyFromDI)
                   {
                              await context.Response.WriteAsync(“API Key Invalid..”);
                              return; 
                   }

                 // 정상적으로 처리되어 다음 미들웨어 호출함(현재 context 를 인자로),
                  await this._next(context); 
           }
}

 ※ context.Response.WriteyAsync();  처리 후 반드시 return 처리 next() 호출 안되게 해야됨
  WriteAsync() 로 이미 응답한상태에서, 다른 미들웨어 또는 함수를 통해 다시 응답함으로써,  응답 헤더를 다시쓰면서
  발생하는오류로 보임 CONNECTION_RESET 클라이언트 오류발생함그러므로 , 요청에 응답처리를 했을경우 반드시    return; 을 통해  next() 함수가 호출되지 않게해야한다. 
  (단, 오류가 없이 응답헤더를 작성하지 않았다면 next() 로 정상호출)

Startup.cs
————————————————————————————————————————————————————-
public static void Configuration(IApplicationBuilder app , IWebHOstEnvironment env)
{
          app.UseMiddleware<MyAPIAuthMiddleware>();
}

 

정리,
사용자 Middleware 를 통해 WebAPI 인증을 거치기 위해서는 먼저 Middleware  in asp.net Core 에서 Middleware 작성

하는 방법을 알아보자.attribute 보다 간단하고, 명료하다.일전에 attribute 를 통해 WebAPI 를 인증하듯, client 의 요청 헤더를 읽어 요청하는 API 키를 가져온다거나 IConfiguration 을 통해 appSetting.json 서버키를 가져오는 로직등은 똑같다.

단, 파이프라인으로 구성된 Middleware 에서는 내가 만든 사용자 Middleware 실행 후 다음 Middleware 를 실행하지 않으면
Middleware 가 단락되므로, 반드시 다음 Middleware 실행을 위해 RequestDelete 를 주입받아, 정상적으로 인증(처리가) 완료되면 next() 호출을 반드시 해줘야 하며, 만약 인증오류 및 조건에 부합하지 않는다면, 직접 Resopnse.WriteAsync() 를 출력하여 사용자에게 메세지를 보내고,, 반드시 return; 시켜,  next() 를 호출 하지 않게 해야한다.

만약, Response.writeAysnc() 를 통해 메세지를 출력하고, next() 호출하게되면::CONNECTION_RESET javascript 오류가발생하고 출력도안되는 현상이 발생한다.이는 Attribute 작성시 next() 호출할때 (여기서 next() 는 미들웨어의 next 와 달리
attribute 를 호출한 클래스나, 메서드 , 인터페이스 를 호출하는 next() 임) context.Result(Content, content-type , StatusCode)가 Null 이 아닐때 오류가 발생하는것과 비슷한것같다.

그러므로 정상적으로 처리가 완료되면 응답헤더는 null 상태여야 한다.

답글 남기기

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