다음을 통해 공유


자습서: .NET 디먼 앱에서 보호된 웹 API 호출

이 자습서는 .NET 디먼 앱에서 보호된 웹 API를 호출하는 방법을 보여 주는 시리즈의 마지막 부분입니다. 이 시리즈 1부에서는 .NET 디먼 앱에 권한을 부여하기 위해 외부 테넌트를 준비했습니다. 이 자습서에서는 클라이언트 디먼 앱을 빌드하고 보호된 웹 API를 호출합니다. 클라이언트 디먼 앱이 자체 ID를 사용하여 액세스 토큰을 획득하도록 설정한 다음, 웹 API를 호출합니다.

이 자습서에서는 다음을 수행합니다.

  • 앱 등록 세부 정보를 사용하도록 디먼 앱을 구성합니다.
  • 자체적으로 토큰을 획득하고 보호된 웹 API를 호출하는 디먼 앱을 빌드합니다.

필수 조건

.NET 디먼 앱 만들기

  1. 터미널을 열고 프로젝트를 사용할 폴더로 이동합니다.

  2. .NET 콘솔 앱을 초기화하고 루트 폴더로 이동합니다.

    dotnet new console -n ToDoListClient
    cd ToDoListClient
    

패키지 설치

Microsoft.Identity.WebMicrosoft.Identity.Web.DownstreamApi 패키지 설치:

dotnet add package Microsoft.Identity.Web
dotnet add package Microsoft.Identity.Web.DownstreamApi

Microsoft.Identity.Web은(는) 인증 미들웨어인 ASP.NET Core와 .NET용 Microsoft 인증 라이브러리(MSAL)를 연결하여 앱에 인증 및 권한 부여 기능을 더 쉽게 추가할 수 있도록 합니다. Microsoft.Identity.Web.DownstreamApi은(는) 다운스트림 API를 호출하는 데 사용되는 인터페이스를 제공합니다.

등록 구성을 추가하는 appsettings.json 파일 생성

  1. 앱의 루트 폴더에 appsettings.json 파일을 만듭니다.

  2. appsettings.json 파일에 앱 등록 세부 정보를 추가합니다.

    {
        "AzureAd": {
            "Authority": "https://<Enter_the_Tenant_Subdomain_Here>.ciamlogin.com/",
            "ClientId": "<Enter_the_Application_Id_here>",
            "ClientCredentials": [
                {
                    "SourceType": "ClientSecret",
                    "ClientSecret": "<Enter_the_Client_Secret_Here>"
                }
            ]
        },
        "DownstreamApi": {
            "BaseUrl": "<Web_API_base_url>",
            "RelativePath": "api/todolist",
            "RequestAppToken": true,
            "Scopes": [
                "api://<Enter_the_Web_Api_Application_Id_Here>/.default"
            ]
        }
    }
    

    다음 값을 사용자의 고유 값으로 바꿉니다.

    설명
    Enter_the_Application_Id_Here 등록한 클라이언트 디먼 앱의 애플리케이션(클라이언트) ID입니다.
    Enter_the_Tenant_Subdomain_Here 디렉터리(테넌트) 하위 도메인입니다.
    Enter_the_Client_Secret_Here 만든 디먼 앱의 비밀 값입니다.
    Enter_the_Web_Api_Application_Id_Here 등록한 웹 API 앱의 애플리케이션(클라이언트) ID입니다.
    Web_API_base_url 웹 API의 기본 URL입니다. 예를 들어, https://localhost:44351/ 여기서 44351은 API가 실행 중인 포트의 포트 번호입니다. 이 값을 얻으려면 API가 이미 실행 중이고 이 단계에서 요청을 기다리고 있어야 합니다.

모델 추가

프로젝트 폴더의 루트로 이동하여 models 폴더를 만듭니다. models 폴더에서 ToDo.cs 파일을 만들고 다음 코드를 추가합니다.

using System;

namespace ToDoListClient.Models;

public class ToDo
{
    public int Id { get; set; }
    public Guid Owner { get; set; }
    public string Description { get; set; } = string.Empty;
}

액세스 토큰 가져오기

이제 디먼 애플리케이션에 필요한 항목을 구성했습니다. 이 단계에서는 디먼 앱이 액세스 토큰을 획득할 수 있도록 하는 코드를 작성합니다.

  1. 코드 편집기에서 program.cs 파일을 열고 해당 내용을 삭제합니다.

  2. 파일에 패키지를 추가합니다.

    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Identity.Abstractions;
    using Microsoft.Identity.Web;
    using ToDoListClient.Models;
    
  3. 토큰 획득 인스턴스를 생성합니다. Microsoft.Identity.Web 패키지의 TokenAcquirerFactory 클래스 GetDefaultInstance 메서드를 사용하여 토큰 획득 인스턴스를 빌드합니다. 기본적으로 인스턴스는 앱과 동일한 폴더에 있는 경우 appsettings.json 파일을 읽습니다. GetDefaultInstance을(를) 사용하면 서비스 컬렉션에 서비스를 추가할 수도 있습니다.

    program.cs 파일에 다음 코드를 추가합니다.

    var tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();
    
  4. 구성에서 읽을 애플리케이션 옵션을 구성하고 DownstreamApi 서비스를 추가합니다. DownstreamApi 서비스는 다운스트림 API를 호출하는 데 사용되는 인터페이스를 제공합니다. config 개체에서 이 서비스 DownstreamAPI를 호출합니다. 디먼 앱은 appsettings.jsonDownstreamApi 섹션에서 다운스트림 API 구성을 읽습니다. 기본적으로 메모리 내 토큰 캐시를 가져옵니다.

    program.cs 파일에 다음 코드 조각을 추가합니다.

    const string ServiceName = "DownstreamApi";
    
    tokenAcquirerFactory.Services.AddDownstreamApi(ServiceName,
        tokenAcquirerFactory.Configuration.GetSection("DownstreamApi"));
    
    
  5. 토큰 획득자를 빌드합니다. Services에 추가한 모든 서비스를 구성하고 서비스 공급자를 반환합니다. 이 서비스 공급자를 사용하여 추가한 API 리소스에 액세스할 수 있습니다. 이 경우 액세스하려는 다운스트림 서비스로 API 리소스를 하나만 추가했습니다.

    program.cs 파일에 다음 코드 조각을 추가합니다.

    var serviceProvider = tokenAcquirerFactory.Build();
    

웹 API 호출

IDownstreamApi 인터페이스를 사용하여 보호된 웹 API를 호출하는 코드를 추가합니다. 이 자습서에서는 할 일 게시에 대한 호출과 모든 할 일 가져오기에 대한 호출만 구현합니다. 샘플 코드에서 삭제 및 배치와 같은 다른 구현을 참조하세요.

program.cs 파일에 다음 코드를 추가합니다.

var toDoApiClient = serviceProvider.GetRequiredService<IDownstreamApi>();

Console.WriteLine("Posting a to-do...");

var firstNewToDo = await toDoApiClient.PostForAppAsync<ToDo, ToDo>(
    ServiceName,
    new ToDo()
    {
        Owner = Guid.NewGuid(),
        Description = "Bake bread"
    });

await DisplayToDosFromServer();
    
async Task DisplayToDosFromServer()
{
    Console.WriteLine("Retrieving to-do's from server...");
    var toDos = await toDoApiClient!.GetForAppAsync<IEnumerable<ToDo>>(
        ServiceName,
        options => options.RelativePath = "/api/todolist"
    );
    
    if (!toDos!.Any())
    {
        Console.WriteLine("There are no to-do's in server");
        return;
    }
    
    Console.WriteLine("To-do data:");
    
    foreach (var toDo in toDos!) {
        DisplayToDo(toDo);
    }
}

void DisplayToDo(ToDo toDo) {
    Console.WriteLine($"ID: {toDo.Id}");
    Console.WriteLine($"User ID: {toDo.Owner}");
    Console.WriteLine($"Message: {toDo.Description}");
}

클라이언트 디먼 앱 실행

데몬 앱의 루트 폴더로 이동하여 다음 명령을 실행합니다.

dotnet run

모든 것이 정상이면 터미널에 다음과 같은 출력이 표시됩니다.

Posting a to-do...
Retrieving to-do's from server...
To-do data:
ID: 1
User ID: 00001111-aaaa-2222-bbbb-3333cccc4444

Message: Bake bread

문제 해결

오류가 발생할 경우,

  • appsettings.json 파일에 추가한 등록 세부 정보를 확인합니다.
  • 올바른 포트 및 https를 통해 웹 API를 호출하고 있는지 확인합니다.
  • 앱 권한이 올바르게 구성되었는지 확인합니다.

전체 샘플 코드는 GitHub에서 사용할 수 있습니다.

리소스 정리

이 자습서에서 등록하고 만든 앱을 사용하지 않으려면 비용을 발생시키지 않도록 삭제합니다.

참고 항목