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

Custom Attribute 를 이용한 WebAPI 인증

<서버 Side>
ㆍ인증에 필요한 클래스 , 메서드등에 Attribute 를 사용하여, 사용전 인증을 거친 클라이언트만 접근 가능하도록 한다.
ㆍAttribute 에서 Http 의 Context 사용, 처리 후 다시 라우팅 할 수 있도록 IAsyncActionFilter 를 상속받아서 구현한다.

ㆍ인증이 필요한 메서드(및 클래스등,,) 요청시 사용자 Attribute 가 요청을 가로채고,
    IAsyncActionFilter 인터페이스의    OnActionExecutionAsync 메서드에서 Context 의 헤더의 ApI-key 의 인증 확인 후
    허용 또는 거부처리를 한다.

<클라이언트  Side>

ㆍ 클라이언트는 Http 헤더에 인증에 필요한 API-Key 와 함께  WebAPI 사용을 요청을 한다.

상속  : Attribute , IAsyncActionFilter  상속 및 OnActionExecutionAsync  구현
설정 : AttributeUsage , AttributeTargets  로 attribute 설정

< 사용자 Attribute  – 기본구조 >
[AttributeUsage(AttributeTargets.Class , Inherited=false , AllowMultiple=false)]
public class MyApiKeyAuthAttribute : Attribute , IAsyncActionFilter 
{
       // IAsyncActionFilter 인터페이스의 OnActionExecutionAsync 구현
       public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
       {
                // context Header  의 Api key 비교 후 인증 처리
       }
}

< Web API >

ㆍ Class 에 Attribute 사용하여 인증처리할때
[MyApiKeyAuth] 
// 클래스 접근 전에 Attribute 에서 인증처라, 클래스 모든 메서드/속성  접근 불가/가능
[ApiController]
[Route(“Api/[controller]”)]
public class MyWebAPIController
{      
     [HttpGet]
     public IEnumable<MyDataList> get()
     {
             
     }

     [MyApiKeyAuth]  // GetForUser  호출시 실행전 MyApiKey가 제어를 가로챈후 attribute 에서 인증 완료후 접근가능
     [HttpGet(“{userid}”)]
     public IEnumable<MyDataList> GetForUser(string userid)
     {
                // MyApiKeyAuth attribute인증이 완료되면 get() 메서드를 정상적으로 호출됨       
     }

     
}

 

< Authenticaltion Attribute >
[MyApiKeyAuth] 로 attribute 를 사용하지만 ,  클래스 작성시 MyApiKeyAttribute 로 작성해주며,
사용시 MyApiKey 만 호출 해도 자동으로 MyApiKeyAttribute 와 매핑되며, attribute 를 생략할수있다.

필요 & 구현 객체 : Attribute , IAsyncActionFilter , AttributeUage , AttributeTargets

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace SecuringWebApiUsingApiKey.Attributes
{

   [AttributeUsage(validOn: AttributeTargets.Method)]
   public class MyApiKeyAttribute : Attribute, IAsyncActionFilter
   {
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {

            if(context.HttpContext.Response.Headers.TryGetValue(“ApiKey” ,out var clientKeyofHeader))
            {
                string serverKey = string.Empty;

                // 의존성 주입(ID) 된 IConfiguration 객체 가져오기(appSetting.json)
                 var appSetting = context.HttpContext.RequestServices.GetRequiredService<IConfiguration>();
                 serverKey = appSetting[“WEBAPI:apiKey”].ToString().Trim();

                 if(!clientKeyofHeader.ToString().Equals(serverKey))
                 {
                       context.Result = new ContentResult()
                       {
                           ContentType = “text/html”,
                            StatusCode = 401,
                            Content = “your api key invalid”
                       };

                     return;
                 }
  
           }
           else
           {
               context.Result = new ContentResult()
               {
                   StatusCode = 401,
                   ContentType = “text/plain”,
                   Content = “your don’t have APIKey”
               };
               return;
           }
       
         await next(); // 현재 attribute 를 호출한 메서드 또는 클래스등이 next() 가 된다.

       }
    }
}

 await next();  가 호출되기 위한 필수조건
Context.Result 는 반드시 null 이어야한다. (기본 null)
★ Context.Result 의 statusCode = 200 (성공) 이어도 InvalidOperationException 예외(오류)가 발생한다
     (그러므로 Context.Result 가 null 이 아니면 반드시 return 문을 통해 next() 가 호출되지 않게 해야한다)
★ context.Result의 ContentResult 객체정보를(content) 채워놓으면 , return 시 별도의 객체를 return 하지 않아도,
    브라우져에 Context.Result 의 정보를  출력하게되어있다.

 

Posted in C#

답글 남기기

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