재우니의 블로그

 

codingsonata.com/secure-asp-net-core-web-api-using-api-key-authentication/#comments

 

Secure ASP.NET Core Web API using API Key Authentication - Coding Sonata

This tutorial explains how to use API Key Authentication to secure your ASP.NET Core Web API using Custom Attribute and Custom Middleware.

codingsonata.com

 

 

API Key Authentication 을 사용하여 ASP.NET Core 웹 API를 쉽게 보호 할 수 있으며 몇 단계 만 수행하면 endpoints 을 보호 할 수 있습니다.

 

이 자습서에서는 API 키를 사용하여 Custom AttributeCustom Middleware의 두 가지 방법으로 ASP.NET Core 웹 API를 보호하는 방법을 설명합니다.

 

API 키 인증 사용은 서비스 클라이언트 또는 잘 알려진 클라이언트로 제한되어야합니다. 즉, API 키 인증을 사용하여 실제로 사용자를 인증하는 것은 권장되지 않으며 주로 식별 및 권한 부여에 사용됩니다. API에 연결되는 프로젝트 또는 서비스.

 

따라서 API와 API 클라이언트 (API에 액세스하는 다른 비즈니스) 간의 보안 링크를 유지합니다.

 

사용자 인증을 포함하려면 OAuth 2.0과 같은 토큰 기반 인증을 적용해야합니다.

 

이는 별도의 자습서가 필요한 매우 중요한 주제입니다.

 

가까운 장래에 ASP.NET Core Web API의 토큰 기반 인증에 대한 몇 가지 사항을 준비 할 것입니다.

 

이제 소개는 짧게 하고 ASP.NET Core 웹 API의 API 키 인증으로 바로 이동하겠습니다.

Visual Studio 2019를 열고 새 프로젝트를 만들고 ASP.NET Core 웹 애플리케이션을 선택하고 최신 버전의 Visual Studio 2019 (16.8.x)를 사용하고 있는지 확인합니다.

 

그런 다음 'SecuringWebApiUsingApiKey' 이름으로 기재하고 Create 합니다.

 

다음 화면에서 템플릿을 API로 선택하고 Create를 누릅니다.

 

 

Visual Studio가 새 프로젝트를 준비 및 초기화하고 준비 할 때까지 잠시 기다리십시오.

로컬 호스트에서 모든 것이 설정되고 준비되었는지 확인하려면 F5 키를 누르거나 실행 버튼을 클릭하여 초기 응용 프로그램을 테스트하십시오.

 

 

아래와 같은 내용이 보이면 모든 준비가 완료된 것이며이 튜토리얼을 시작할 준비가 된 것입니다.

 

 

기본 템플릿 WeatherforecastController 는 API 키 인증을 사용하여 ASP.NET Web API 를 보호 할 수 있는지 방법을 보여주기 위해 사용할 것이므로 삭제하지 말고 그대로 둡니다.

 

API 키 인증을 구현하는 방법에는 여러 가지가 있지만이 자습서에서는이를 달성하는 두 가지 방법을 설명합니다.

 

 

 

Custom Attributes 사용

 

 

이제 ASP.NET Core Attributes 에서 상속하고 IAsyncActionResult 인터페이스를 구현하는 새 사용자 지정 Attributes 을 도입하려고합니다.

 

ApiKey Header 가 존재하고 값이 있으며 그 값이 실제로 올바른 API 키인지 확인합니다. 그렇지 않으면 요청이 end point 에 액세스 할 권한이 없음을 나타내는 401 Unauthorized 응답을 클라이언트에 반환합니다

 

따라서 Attribute 을 추가해 보겠습니다.

Attributes 로 폴더명을 기재후 생성합니다.

그런 다음 속성 폴더를 마우스 오른쪽 버튼으로 클릭하고 추가를 선택한 다음 새 항목…

속성 이름을 ApiKeyAttribute 로 지정 하겠습니다.

이제 아래와 같이 Attributes 폴더 아래에 새로운 클래스가 있어야합니다.

 

이 Attribute 을 사용하여 컨트롤러에 기재하여 Attribute 컨트롤러로 라우팅되는 모든 요청이 ApiKeyAttribute로 리디렉션되도록 할 것입니다.

 

사용자 지정 Attributes 은 Global System.Attribute의 기본 추상 클래스 Attribute에서 상속되며, 이는 클래스를 사용자 지정 Attributes 으로 변환합니다.

 

또한 IAsyncActionFilter 인터페이스를 구현하여 사용자 지정 Attributes 이 호출 요청을 가로 채고 처리 한 다음, 요청을 컨트롤러로 다시 라우팅 할 수 있도록 합니다.

 

이제 custom attributes 에서 수행 할 작업을 살펴 ​​보겠습니다.

 

 

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

namespace SecuringWebApiUsingApiKey.Attributes
{
    [AttributeUsage(validOn: AttributeTargets.Class)]
    public class ApiKeyAttribute : Attribute, IAsyncActionFilter
    {
        private const string APIKEYNAME = "ApiKey";
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            if (!context.HttpContext.Request.Headers.TryGetValue(APIKEYNAME, out var extractedApiKey))
            {
                context.Result = new ContentResult()
                {
                    StatusCode = 401,
                    Content = "Api Key was not provided"
                };
                return;
            }

            var appSettings = context.HttpContext.RequestServices.GetRequiredService<IConfiguration>();

            var apiKey = appSettings.GetValue<string>(APIKEYNAME);

            if (!apiKey.Equals(extractedApiKey))
            {
                context.Result = new ContentResult()
                {
                    StatusCode = 401,
                    Content = "Api Key is not valid"
                };
                return;
            }

            await next();
        }
    }
}

 

 

구현한 코드에 대한 설명은 아래와 같습니다.

 

[AttributeUsage(validOn: AttributeTargets.Class)]

 

이 데코레이션은 ApiKeyAttribute 가 사용되는 위치를 표시하고 지정하는 속성이기도합니다. 

ApiKeyAttribute가 Controllers 와 같은 클래스에서만 사용되도록 지정했습니다.

 

AttributeTargets는 플래그를 적용하는 열거 형이므로 파이프 | 연산자 (비트 또는)를 사용하여 사용자 지정 Attributes 에 대한 더 많은 사용을 지정하므로 아래는 ApiKeyAttribute가 클래스 및 / 또는 메서드 (컨트롤러 및 / 또는 작업 메서드) 모두에서 사용될 수 있음을 나타냅니다.

 

[AttributeUsage(validOn: AttributeTargets.Class | AttributeTargets.Method)]

 

이제 코드의 첫 번째 논리 섹션을 설명하겠습니다

 

if (!context.HttpContext.Request.Headers.TryGetValue(APIKEYNAME, out var extractedApiKey))
{
  context.Result = new ContentResult()
  {
    StatusCode = 401,
    Content = "Api Key was not provided"
  };
  return;
}

 

위 코드에서 이름이 ApiKey 인 키가있는 경우 요청 헤더 컬렉션 개체를 먼저 확인합니다. 물론 원하는 헤더 이름을 사용할 수 있으며 일부는 AWS API Gateway의 기본 헤더이기 때문에 X-API-Key를 사용하는 것을 선호합니다.

이제 헤더에 ApiKey가 키로 포함되지 않은 경우 API 키가 제공되지 않았다는 메시지와 함께 401 Unauthorized 응답 코드를 반환합니다.

 

Content 필드를 비워 두거나 StatusCode 및 Content를 지정하지 않고 ContentResult 대신 UnauthorizedResult 만 반환하면 메시지없이 401 만 반환됩니다.

 

ApiKey 헤더가 전송 된 경우 ApiKey 헤더 의 값이 API 프로젝트에 정의 된 ApiKey와 일치하는지 확인하는 다음 단계로 이동합니다 .

 

이제 API 키를 생성 해 보겠습니다. 이 자습서에서는 ASP.NET Core Web API 프로젝트에있는 설정 파일 인 appsettings.json 파일에 API 키를 추가합니다.

 

그래서 그것을 열고 아래와 같이 ApiKey 설정을 추가합시다.

 

 

메모:

 

추측과 무작위를 더 쉽게 만들기 위해 항상 충분히 강력한 API 키 (임의의 고유 한 긴 숫자의 영숫자 조합)를 선택하는 것이 중요합니다.

또 다른 참고 사항은 하나 이상의 클라이언트와 동일한 API 키를 공유하지 않는 것입니다. API 키의 목적은 클라이언트 또는 프로젝트를 인증하는 것이므로 클라이언트별로 고유하게 유지해야합니다.

이제 예제로 돌아가 나머지 방법을 설명하겠습니다.

 

ASP.NET Core Web API 프로젝트에서 appsettings.json 파일을 읽는 방법에는 여러 가지가 있지만 Microsoft의 종속성 주입 및 구성 확장 라이브러리를 사용하여 설정 파일을로드하고 해당 값을 읽을 수 있습니다.

 

var appSettings = context.HttpContext.RequestServices.GetRequiredService<IConfiguration>();

var apiKey = appSettings.GetValue<string>(APIKEYNAME);

 

이제 appsettings.json 파일에 정의 된 API 키 값을 얻었으므로 요청 헤더 컬렉션에서 추출한 API 키 값과 비교합니다. 둘 다 일치하면 요청을 컨트롤러로 라우팅하여 의도 된 http 작업 (get, post… 등)을 실행하는 것이 좋습니다.

그렇지 않으면 401 Unauthorized 응답과 클라이언트가 권한이 없음을 나타내는 메시지와 함께 요청이 실패합니다.

 

if (!apiKey.Equals(extractedApiKey))
{
  context.Result = new ContentResult()
  {
    StatusCode = 401,
    Content = "Unauthorized client"
  };
  return;
}

 

장식

 

이제 여기서 원하는 마지막 부분은 엔드 포인트를 호출하는 클라이언트를 인증 할 수 있도록 ApiKey 속성으로 컨트롤러를 장식해야한다는 것입니다.

따라서 WeatherForecastController를 열고 WeatherForecastController 클래스 위에 [ApiKey]를 추가합니다.

 

[ApiKey]
public class WeatherForecastController : ControllerBase

 

 

컨트롤러 클래스의 맨 위에 새 네임 스페이스를 포함해야합니다.

 

이제 애플리케이션을 실행하고 브라우저에서 메시지를 확인합니다.

 

Postman에서 테스트

 

무슨 일이 일어나고 있는지 더 잘 파악하고 테스트 매개 변수를 제어하기 위해 Postman을 사용할 것입니다.

브라우저에서 로컬 호스트를 계속 실행하고 Postman을 엽니 다.

이제 헤더에 아무것도 보내지 않고 동일한 URL을 실행 해 보겠습니다. 상태가 401 Unauthorized이고 응답 본문에 "Api Key was not provided"메시지가 표시됩니다.

401 Unauthorized. API 키가 제공되지 않았습니다.

 

이제 올바른 헤더 이름을 보내려고하지만 값이 잘못되면 401과 동일한 Status를 얻지 만 실제 ApiKey 헤더를 보내는 첫 번째 단계를 통과했기 때문에 메시지가 달라 지지만 그 값은 그렇지 않습니다. 옳은:

401 Unauthorized. 승인되지 않은 클라이언트.

 

이제 헤더에 올바른 API 키를 전송하여 클라이언트가 유효성 검사를 통과하도록하겠습니다.

 

200 OK

 

 

이제 응답 코드가 200 OK이고 응답 본문은 / weatherforecast 끝점의 기본 GET 메서드에서 반환 된 실제 데이터입니다.

 

 


 

Custom Middleware 사용

 

 

사용자 지정 ASP.NET Core Middleware를 사용하면 단일 위치에서 요청 개체를 가로 채서 처리 할 수 ​​있습니다.

게시 된 웹 API로 전달되는 모든 요청을 가로 채서 요청 헤더 컬렉션을 탭하고 API 키 헤더를 검색하고 값을 확인할 수 있습니다.

따라서 우리는 custom attribute 에서 했던 것과 거의 똑같은 로직을 수행하지만 이번에는 Middleware 내에서 수행 할 것입니다.

이름이 Middleware 인 새 폴더를 만든 다음 이름이 ApiKeyMiddleware 인 C # 클래스 파일을 생성하여 시작하겠습니다.

 

 

Middleware를 정의하는 것은 RequestDelegate 클래스의 인스턴스를 사용하는 생성자이며,이 인스턴스는 실제로 ASP.NET Core Middleware컬렉션간에 전달되는 파이프 라인입니다. 따라서이 커스텀 Middleware도 이 파이프 라인 인스턴스를 수신하고 이에 대해 몇 가지 작업을 수행합니다.

 

다음으로 중요한 것은이 Middleware 에서 정의해야하는 InvokeAsync 메서드로, 기본 프로세스를 포함하고 우리의 경우 기본 프로세스는 httpcontext 요청 헤더 컬렉션 내에서 ApiKey 헤더 이름과 값을 검색하고 유효성을 검사하는 것입니다. 그래서 이것은 메소드 인수에 전달되어야합니다.

 

using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System.Threading.Tasks;

namespace SecuringWebApiUsingApiKey.Middleware
{
    public class ApiKeyMiddleware
    {
        private readonly RequestDelegate _next;
        private const string APIKEYNAME = "ApiKey";
        public ApiKeyMiddleware(RequestDelegate next)
        {
            _next = next;
        }
        public async Task InvokeAsync(HttpContext context)
        {
            if (!context.Request.Headers.TryGetValue(APIKEYNAME, out var extractedApiKey))
            {
                context.Response.StatusCode = 401;
                await context.Response.WriteAsync("Api Key was not provided. (Using ApiKeyMiddleware) ");
                return;
            }

            var appSettings = context.RequestServices.GetRequiredService<IConfiguration>();

            var apiKey = appSettings.GetValue<string>(APIKEYNAME);

            if (!apiKey.Equals(extractedApiKey))
            {
                context.Response.StatusCode = 401;
                await context.Response.WriteAsync("Unauthorized client. (Using ApiKeyMiddleware)");
                return;
            }

            await _next(context);
        }
    }
}

 

 

custom attribute 에서 수행 한 작업과 유사하지만 여기서 눈에 띄는 주요 차이점은 컨텍스트의 Response 객체를 직접 설정할 수 없지만 상태 코드와 메시지를 별도로 할당해야한다는 것입니다.

 

context.Response.StatusCode = 401;
await context.Response.WriteAsync("Api Key was not provided. (Using ApiKeyMiddleware)");

 

이제 Middleware 를 파이프 라인에 삽입하거나 포함해야합니다. Startup.cs 클래스에서이 작업을 수행합니다.

Configure 메서드에 다음 줄을 추가합니다.

 

app.UseMiddleware<ApiKeyMiddleware>();

 

 

 

이렇게하면 custom attributes 과 같은 특정 컨트롤러 나 메서드뿐만 아니라 프로젝트의 모든 단일 컨트롤러에이 사용자 지정 API 키 Middleware 를 적용 할 수 있습니다.

 

Middleware 는 모든 API에 로깅 및 일반 예외 처리를 적용하려는 경우와 같은 다른 상황에서도 매우 유용합니다. ASP.NET Core Middleware 를 사용하기위한 사용 사례가 너무 많습니다 .

 

이제 애플리케이션을 다시 실행하기 직전에 WeatherForecastController에서 [ApiKey] 속성을 제거하여 새 Middleware 를 테스트 할 수 있도록합니다.

이제 애플리케이션을 실행 해 보겠습니다.

 

401 Unauthorized. API 키가 제공되지 않았습니다. (ApiKeyMiddleware 사용)

 

401 Unauthorized. 승인되지 않은 클라이언트. (ApiKeyMiddleware 사용)

 

200 OK

 

이렇게하면 custom attribute 처럼 특정하지 않고 모든 단일 endpoints 에 http 메시지 처리기를 적용 할 수 있습니다. 여기서 선택한 endpoint 을 custom attribute 으로 장식하여 API 키를 확인할 수 있습니다.

 

요약

 

API 키 인증을 사용하여 ASP.NET Core 웹 API를 보호하는 방법에 대한 예제를 통해 논의하고 설명했습니다. 이 자습서에서는 API 키 인증을 구현하는 두 가지 방법 인 custom attributescustom Middleware 를 보여주었습니다. 

 

둘 다 API 와 API 클라이언트간에 이러한 종류의 인증을 달성하는 매우 훌륭하고 효과적인 방법입니다.

 

 

 

 Github 저장소 에서 전체 소스 코드를 찾을 수 있습니다.

 

aram87/SecuringWebApiUsingApiKey

Contribute to aram87/SecuringWebApiUsingApiKey development by creating an account on GitHub.

github.com

 

 

참고 :이 기사와 GitHub의 소스 코드는 .NET 5로 업데이트되었습니다. Microsoft와 커뮤니티에서 중요한 업데이트가 발표 될 때마다 계속 업데이트하겠습니다.

 

 

ASP.NET Core에 대한 다른 기사 확인

ASP.NET Core 및 Entity Framework Core를 사용하여 RESTful API 빌드

IIS에 ASP.NET Core Web Api 배포