다음을 통해 공유


인증 및 권한 부여

이 콘텐츠는 ‘.NET MAUI를 사용하는 엔터프라이즈 애플리케이션 패턴’ eBook에서 발췌한 것으로, .NET Docs에서 제공되거나 오프라인으로 읽을 수 있는 다운로드 가능한 무료 PDF로 제공됩니다.

Enterprise Application Patterns Using .NET MAUI eBook cover thumbnail.

인증은 사용자로부터 이름 및 암호와 같은 식별 자격 증명을 획득하고 특정 권한과 대조해 해당 자격 증명의 유효성을 검사하는 프로세스입니다. 자격 증명이 유효한 경우 자격 증명을 제출한 엔터티는 인증된 ID로 간주됩니다. ID가 설정되면 권한 부여 프로세스는 해당 ID가 특정 리소스에 액세스할 수 있는지 여부를 확인합니다.

ASP.NET Core ID, 외부 인증 공급자(예: Microsoft, Google, Facebook 또는 Twitter) 및 인증 미들웨어를 포함해 ASP.NET 웹 애플리케이션과 통신하는 .NET MAUI 앱에 인증 및 권한 부여를 통합하는 방법은 여러 가지가 있습니다. eShopOnContainers 다중 플랫폼 앱은 IdentityServer 4를 사용하는 컨테이너화된 ID 마이크로 서비스를 사용하여 인증 및 권한 부여를 수행합니다. 앱은 IdentityServer에서 보안 토큰을 요청하여 사용자를 인증하거나 리소스에 액세스합니다. IdentityServer가 사용자를 대신하여 토큰을 발급하려면 사용자가 IdentityServer에 로그인해야 합니다. 그러나 IdentityServer는 인증을 위해 사용자 인터페이스 또는 데이터베이스를 제공하지 않습니다. 따라서 eShopOnContainers 참조 애플리케이션에서 ASP.NET Core ID가 이러한 목적으로 사용됩니다.

인증

애플리케이션이 현재 사용자의 ID를 알아야 하는 경우 인증이 필요합니다. 사용자를 식별하는 ASP.NET Core의 기본 메커니즘은 개발자가 구성한 데이터 저장소에 사용자 정보를 저장하는 ASP.NET Core ID 멤버 자격 시스템입니다. 일반적으로 이 데이터 저장소는 EntityFramework 저장소이지만 사용자 지정 저장소 또는 타사 패키지를 사용하여 Azure Storage, DocumentDB 또는 기타 위치에 ID 정보를 저장할 수 있습니다.

로컬 사용자 데이터 저장소를 사용하고 (ASP.NET 웹 애플리케이션에서 전형적인 방식인) 쿠키를 통해 요청 간에 ID 정보를 유지하는 인증 시나리오의 경우 ASP.NET Core ID는 적합한 솔루션입니다. 그러나 쿠키는 데이터를 유지하고 전송하는 자연스러운 방법이 아닐 때도 있습니다. 예를 들어 앱에서 액세스하는 RESTful 엔드포인트를 노출하는 ASP.NET Core 웹 애플리케이션은 이 시나리오에서 쿠키를 사용할 수 없으므로 일반적으로 전달자 토큰 인증을 사용해야 합니다. 그러나 전달자 토큰을 쉽게 검색하고 앱에서 만든 웹 요청의 권한 부여 헤더에 포함할 수 있습니다.

IdentityServer 4를 사용하여 전달자 토큰 발급

IdentityServer 4는 ASP.NET Core에 대한 오픈 소스 OpenID Connect 및 OAuth 2.0 프레임워크에 속하며, 로컬 ASP.NET Core ID 사용자에 대한 보안 토큰 발급을 포함하여 많은 인증 및 권한 부여 시나리오에 사용할 수 있습니다.

참고

OpenID Connect와 OAuth 2.0은 매우 비슷하지만 책임이 다릅니다.

OpenID Connect는 OAuth 2.0 프로토콜을 기반으로 하는 인증 계층입니다. OAuth 2는 애플리케이션이 보안 토큰 서비스에서 액세스 토큰을 요청하고 이를 사용하여 API와 통신할 수 있도록 하는 프로토콜입니다. 이 위임은 인증 및 권한 부여를 중앙 집중화할 수 있으므로 클라이언트 애플리케이션과 API의 복잡성을 줄입니다.

OpenID Connect 및 OAuth 2.0은 인증과 API 액세스의 두 가지 기본 보안 문제를 결합하며 IdentityServer 4는 이러한 프로토콜을 구현한 것입니다.

eShopOnContainers 참조 애플리케이션과 같이 클라이언트-마이크로 서비스 간 직접 통신을 사용하는 애플리케이션에서는 다음 다이어그램에서 보는 것처럼 STS(보안 토큰 서비스)로 작동하는 전용 인증 마이크로 서비스를 사용하여 사용자를 인증할 수 있습니다. 클라이언트-마이크로 서비스 간 직접 통신에 관한 자세한 내용은 마이크로 서비스를 참조하세요.

Authentication by a dedicated authentication microservice.

eShopOnContainers 다중 플랫폼 앱은 IdentityServer 4를 사용하여 인증을 수행하고 API에 대한 액세스 제어를 사용하는 ID 마이크로 서비스와 통신합니다. 따라서 다중 플랫폼 앱은 사용자를 인증하거나 리소스에 액세스하기 위해 IdentityServer에서 토큰을 요청합니다.

  • IdentityServer를 사용하여 사용자를 인증하는 작업은 인증 프로세스의 결과를 나타내는 ID 토큰을 요청하는 다중 플랫폼 앱에서 수행합니다. 최소한 사용자의 식별자와 사용자를 인증하는 방법 및 시기에 관한 정보가 포함됩니다. 이는 추가 ID 데이터를 포함할 수도 있습니다.
  • IdentityServer를 사용하여 리소스에 액세스하는 작업은 API 리소스에 대한 액세스를 허용하는 액세스 토큰을 요청하는 다중 플랫폼 앱에서 수행합니다. 클라이언트는 액세스 토큰을 요청하여 이를 API에 전달합니다. 액세스 토큰에는 클라이언트 및 사용자(있는 경우)에 관한 정보가 포함됩니다. 그런 다음, API는 해당 정보를 사용하여 데이터에 대한 액세스 권한을 부여합니다.

참고

토큰을 성공적으로 요청하려면 먼저 클라이언트를 IdentityServer에 등록해야 합니다. 클라이언트 추가에 관한 자세한 내용은 클라이언트 정의를 참조하세요.

웹 애플리케이션에 IdentityServer 추가

ASP.NET Core 웹 애플리케이션이 IdentityServer 4를 사용하려면 웹 애플리케이션의 Visual Studio 솔루션에 추가해야 합니다. 자세한 내용은 IdentityServer 설명서의 설정 및 개요를 참조하세요. IdentityServer가 웹 애플리케이션의 Visual Studio 솔루션에 포함되면 OpenID Connect 및 OAuth 2.0 엔드포인트에 대한 요청을 처리하기 위해 HTTP 요청 처리 파이프라인에 추가해야 합니다. 이는 다음 코드 예제에서 설명한 것처럼 웹 애플리케이션의 Startup 클래스에 있는 Configure 메서드에서 수행됩니다.

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    app.UseIdentity();
}

순서는 웹 애플리케이션의 HTTP 요청 처리 파이프라인에서 중요합니다. 따라서 로그인 화면을 구현하는 UI 프레임워크에 앞서 IdentityServer를 파이프라인에 추가해야 합니다.

IdentityServer 구성

eShopOnContainers 참조 애플리케이션의 다음 코드 예제에 설명된 대로 services.AddIdentityServer 메서드를 호출하여 웹 애플리케이션의 Startup 클래스에 있는 ConfigureServices 메서드에서 IdentityServer를 구성해야 합니다.

public void ConfigureServices(IServiceCollection services)
{
    services
        .AddIdentityServer(x => x.IssuerUri = "null")
        .AddSigningCredential(Certificate.Get())
        .AddAspNetIdentity<ApplicationUser>()
        .AddConfigurationStore(builder =>
            builder.UseSqlServer(connectionString, options =>
                options.MigrationsAssembly(migrationsAssembly)))
        .AddOperationalStore(builder =>
            builder.UseSqlServer(connectionString, options =>
                options.MigrationsAssembly(migrationsAssembly)))
        .Services.AddTransient<IProfileService, ProfileService>();
}

services.AddIdentityServer 메서드를 호출한 후 다음을 구성하기 위해 추가 흐름 API가 호출됩니다.

  • 서명에 사용되는 자격 증명
  • 사용자의 요청에 따라 액세스할 수 있는 API 및 ID 리소스
  • 토큰을 요청하기 위해 연결되는 클라이언트
  • ASP.NET Core ID

IdentityServer 4 구성을 동적으로 로드합니다. IdentityServer 4의 API를 사용하면 구성 개체의 메모리 내 목록에서 IdentityServer를 구성할 수 있습니다. eShopOnContainers 참조 애플리케이션에서 이러한 메모리 내 컬렉션은 애플리케이션에 하드 코딩됩니다. 그러나 프로덕션 시나리오에서 이러한 컬렉션은 구성 파일 또는 데이터베이스에서 동적으로 로드할 수 있습니다.

ASP.NET Core ID를 사용하도록 IdentityServer를 구성하는 방법에 관한 자세한 내용은 IdentityServer 설명서에서 ASP.NET Core ID 사용을 참조하세요.

API 리소스 구성

API 리소스를 구성할 때 AddInMemoryApiResources 메서드는 IEnumerable<ApiResource> 컬렉션을 예상합니다. 다음 코드 예제에서는 eShopOnContainers 참조 애플리케이션에서 이 컬렉션을 제공하는 GetApis 메서드를 보여줍니다.

public static IEnumerable<ApiResource> GetApis()
{
    return new List<ApiResource>
    {
        new ApiResource("orders", "Orders Service"),
        new ApiResource("basket", "Basket Service")
    };
}

이 메서드는 IdentityServer가 순서와 basket API를 보호하도록 지정합니다. 따라서 이러한 API를 호출할 때에는 IdentityServer 관리형 액세스 토큰이 필요합니다. ApiResource 형식에 관한 자세한 내용은 IdentityServer 4 설명서의 API 리소스를 참조하세요.

ID 리소스 구성

ID 리소스를 구성할 때 AddInMemoryIdentityResources 메서드는 IEnumerable<IdentityResource> 컬렉션을 예상합니다. ID 리소스는 사용자 ID, 이름 또는 이메일 주소와 같은 데이터입니다. 각 ID 리소스에는 고유한 이름이 있고 임의의 클레임 형식을 할당할 수 있는데, 이는 사용자의 ID 토큰에 포함됩니다. 다음 코드 예제에서는 eShopOnContainers 참조 애플리케이션에서 이 컬렉션을 제공하는 GetResources 메서드를 보여줍니다.

public static IEnumerable<IdentityResource> GetResources()
{
    return new List<IdentityResource>
    {
        new IdentityResources.OpenId(),
        new IdentityResources.Profile()
    };
}

OpenID Connect 사양은 일부 표준 ID 리소스를 지정합니다. 최소 요구 사항은 사용자에 대한 고유 ID를 내보내기 위한 지원이 제공된다는 것입니다. IdentityResources.OpenId ID 리소스를 노출하여 이 작업을 수행합니다.

참고

IdentityResources 클래스는 OpenID Connect 사양(openid, 이메일, 프로필, 전화 및 주소)에 정의된 모든 범위를 지원합니다.

IdentityServer는 사용자 지정 ID 리소스 정의도 지원합니다. 자세한 내용은 IdentityServer 설명서에서 사용자 지정 ID 리소스 정의를 참조하세요. IdentityResource 형식에 관한 자세한 내용은 IdentityServer 4 설명서의 ID 리소스를 참조하세요.

클라이언트 구성

클라이언트는 IdentityServer에서 토큰을 요청할 수 있는 애플리케이션입니다. 일반적으로 각 클라이언트에 대해 최소한 다음과 같은 설정을 정의해야 합니다.

  • 고유한 클라이언트 ID
  • 토큰 서비스와 허용되는 상호 작용(‘권한 부여 유형’이라고 함)
  • ID 및 액세스 토큰이 전송되는 위치(‘리디렉션 URI’라고 함)
  • 클라이언트가 액세스할 수 있는 리소스 목록(‘범위’라고 함)

클라이언트를 구성할 때 AddInMemoryClients 메서드는 IEnumerable<Client> 컬렉션을 예상합니다. 다음 코드 예제에서는 eShopOnContainers 참조 애플리케이션 내에서 이 컬렉션을 제공하는 GetClients 메서드의 eShopOnContainers 다중 플랫폼 앱에 대한 구성을 보여줍니다.

public static IEnumerable<Client> GetClients(Dictionary<string,string> clientsUrl)
{
    return new List<Client>
    {
        // Omitted for brevity
        new Client
        {
            ClientId = "xamarin",
            ClientName = "eShop Xamarin OpenId Client",
            AllowedGrantTypes = GrantTypes.Hybrid,
            ClientSecrets =
            {
                new Secret("secret".Sha256())
            },
            RedirectUris = { clientsUrl["Xamarin"] },
            RequireConsent = false,
            RequirePkce = true,
            PostLogoutRedirectUris = { $"{clientsUrl["Xamarin"]}/Account/Redirecting" },
            AllowedCorsOrigins = { "http://eshopxamarin" },
            AllowedScopes = new List<string>
            {
                IdentityServerConstants.StandardScopes.OpenId,
                IdentityServerConstants.StandardScopes.Profile,
                IdentityServerConstants.StandardScopes.OfflineAccess,
                "orders",
                "basket"
            },
            AllowOfflineAccess = true,
            AllowAccessTokensViaBrowser = true
        },
    };
}

이 구성은 다음 속성에 대한 데이터를 지정합니다.

속성 설명
ClientId 클라이언트의 고유 ID
ClientName 로깅 및 동의 화면에 사용되는 클라이언트 표시 이름
AllowedGrantTypes 클라이언트가 필요에 따라 IdentityServer와 상호 작용하는 방법을 지정합니다. 자세한 내용은 인증 흐름 구성을 참조하세요.
ClientSecrets 토큰 엔드포인트에서 토큰을 요청할 때 사용되는 클라이언트 암호 자격 증명을 지정합니다.
RedirectUris 토큰 또는 인증 코드를 반환할 수 있는 URI를 지정합니다.
RequireConsent 동의 화면이 필요한지 여부를 지정합니다.
RequirePkce 인증 코드를 사용하는 클라이언트가 증명 키를 보내야 하는지 여부를 지정합니다.
PostLogoutRedirectUris 로그아웃 후 리디렉션할 수 있는 URI를 지정합니다.
AllowedCorsOrigins IdentityServer가 원본에서 원본 간 호출을 허용할 수 있도록 클라이언트의 원본을 지정합니다.
AllowedScopes 클라이언트가 액세스할 수 있는 리소스를 지정합니다. 기본적으로 클라이언트는 리소스에 액세스할 수 없습니다.
AllowOfflineAccess 클라이언트가 새로 고침 토큰을 요청할 수 있는지 여부를 지정합니다.

인증 흐름 구성

클라이언트와 IdentityServer 간의 인증 흐름은 Client.AllowedGrantTypes 속성에 권한 부여 유형을 지정하여 구성할 수 있습니다. OpenID Connect 및 OAuth 2.0 사양은 다음을 포함한 여러 인증 흐름을 정의합니다.

인증 흐름 설명
암시적 이 흐름은 브라우저 기반 애플리케이션에 최적화되어 있으며 사용자 인증 전용 또는 인증 및 액세스 토큰 요청에 사용해야 합니다. 모든 토큰은 브라우저를 통해 전송되므로 새로 고침 토큰과 같은 고급 기능은 허용되지 않습니다.
인증 코드 이 흐름은 클라이언트 인증을 지원하면서 브라우저 전면 채널이 아닌 백 채널에서 토큰을 검색하는 기능을 제공합니다.
하이브리드 이 흐름은 암시적 코드 부여 형식과 인증 코드 부여 형식의 조합입니다. ID 토큰은 브라우저 채널을 통해 전송되며 서명된 프로토콜 응답 및 인증 코드와 같은 기타 아티팩트를 포함합니다. 응답의 유효성을 성공적으로 검사한 후 백 채널을 사용하여 액세스 및 새로 고침 토큰을 검색해야 합니다.

하이브리드 인증 흐름을 사용하는 것이 좋습니다. 하이브리드 인증 흐름은 브라우저 채널에 가해지는 여러 공격을 완화하며 액세스 토큰(및 가능하다면 새로 고침 토큰)을 검색하려는 네이티브 애플리케이션에 권장되는 흐름입니다.

인증 흐름에 관한 자세한 내용은 IdentityServer 4 설명서의 권한 부여 유형을 참조하세요.

인증 수행

IdentityServer가 사용자를 대신하여 토큰을 발급하려면 사용자가 IdentityServer에 로그인해야 합니다. 그러나 IdentityServer는 인증을 위해 사용자 인터페이스 또는 데이터베이스를 제공하지 않습니다. 따라서 eShopOnContainers 참조 애플리케이션에서 ASP.NET Core ID가 이러한 목적으로 사용됩니다.

eShopOnContainers 다중 플랫폼 앱은 아래 다이어그램에 나와 있는 하이브리드 인증 흐름을 사용하여 IdentityServer로 인증합니다.

High-level overview of the sign in process.

<base endpoint>:5105/connect/authorize에 대한 로그인 요청이 이루어집니다. 인증에 성공한 후 IdentityServer는 인증 코드와 ID 토큰이 포함된 인증 응답을 반환합니다. 인증 코드는 액세스, ID 및 새로 고침 토큰으로 응답하는 <base endpoint>:5105/connect/token으로 전송됩니다.

eShopOnContainers 다중 플랫폼 앱은 추가 매개 변수를 사용하여 <base endpoint>:5105/connect/endsession에 요청을 전송하여 IdentityServer에서 로그아웃합니다. 로그아웃 후 IdentityServer는 로그아웃 후 리디렉션 URI를 다중 플랫폼 앱으로 다시 전송하여 응답합니다. 이 프로세스를 다이어그램으로 나타내면 아래와 같습니다.

High-level overview of the sign out process.

eShopOnContainers 다중 플랫폼 앱에서 IdentityServer와의 통신은 IIdentityService 인터페이스를 구현하는 IdentityService 클래스에서 수행합니다. 이 인터페이스는 구현 클래스가 CreateAuthorizationRequest, CreateLogoutRequestGetTokenAsync 메서드를 제공해야 한다고 지정합니다.

로그인

사용자가 LoginViewLOGIN 단추를 탭하면 LoginViewModel 클래스의 SignInCommand가 실행되어 SignInAsync 메서드가 실행됩니다. 다음 코드 예제에서는 이 메서드를 보여줍니다.

private async Task SignInAsync()
{
    await IsBusyFor(
        async () =>
        {
            LoginUrl = _identityService.CreateAuthorizationRequest();

            IsValid = true;
            IsLogin = true;
        });
}

이 메서드는 다음 코드 예제에서 보는 것처럼 IdentityService 클래스에서 CreateAuthorizationRequest 메서드를 호출합니다.

public string CreateAuthorizationRequest()
{
    // Create URI to authorization endpoint
    var authorizeRequest = new AuthorizeRequest(GlobalSetting.Instance.IdentityEndpoint);
    // Dictionary with values for the authorize request
    var dic = new Dictionary<string, string>();
    dic.Add("client_id", GlobalSetting.Instance.ClientId);
    dic.Add("client_secret", GlobalSetting.Instance.ClientSecret); 
    dic.Add("response_type", "code id_token");
    dic.Add("scope", "openid profile basket orders locations marketing offline_access");
    dic.Add("redirect_uri", GlobalSetting.Instance.IdentityCallback);
    dic.Add("nonce", Guid.NewGuid().ToString("N"));
    dic.Add("code_challenge", CreateCodeChallenge());
    dic.Add("code_challenge_method", "S256");
    // Add CSRF token to protect against cross-site request forgery attacks.
    var currentCSRFToken = Guid.NewGuid().ToString("N");
    dic.Add("state", currentCSRFToken);
    
    var authorizeUri = authorizeRequest.Create(dic); 
    return authorizeUri;
}

이 메서드는 필요한 매개 변수를 사용하여 IdentityServer의 권한 부여 엔드포인트에 대한 URI를 만듭니다. 권한 부여 엔드포인트는 사용자 설정으로 노출되는 기본 엔드포인트의 포트 5105에서 /connect/authorize에 위치합니다. 사용자 설정에 관한 자세한 내용은 구성 관리를 참조하세요.

참고

OAuth에 대한 PKCE(코드 교환용 증명 키) 확장을 구현하면 eShopOnContainers 다중 플랫폼 앱의 공격 표면이 감소합니다. PKCE는 가로챈 인증 코드를 함부로 사용하지 못하도록 보호합니다. 이러한 보호는 클라이언트가 비밀 검증 도구 즉, 권한 부여 요청에 전달되는 해시를 생성하여 이루어지며, 이 해시는 인증 코드를 사용할 때 해시되지 않은 상태로 표시됩니다. PKCE에 관한 자세한 내용은 인터넷 엔지니어링 태스크 포스 웹 사이트에서 OAuth 공용 클라이언트의 코드 교환에 대한 증명 키를 참조하세요.

반환된 URI는 LoginViewModel 클래스의 LoginUrl 속성에 저장됩니다. IsLogin 속성이 true가 되면 LoginViewWebView가 표시됩니다. WebView 데이터는 LoginUrl 속성이 IdentityServer의 권한 부여 엔드포인트로 설정된 경우 해당 Source 속성을 LoginViewModel 클래스의 LoginUrl 속성과 IdentityServer에 대한 로그인 요청에 바인딩합니다. IdentityServer가 이 요청을 수신하고 사용자가 인증되지 않은 경우 WebView는 아래 이미지에 표시된 구성된 로그인 페이지로 리디렉션됩니다.

Login page displayed by the WebView.

로그인이 완료되면 WebView는 반환 URI로 리디렉션됩니다. 이 WebView 탐색을 수행하면 다음 코드 예제와 같이 LoginViewModel 클래스의 NavigateAsync 메서드가 실행됩니다.

private async Task NavigateAsync(string url)
{
    var unescapedUrl = System.Net.WebUtility.UrlDecode(url);

    if (unescapedUrl.Equals(GlobalSetting.Instance.LogoutCallback, StringComparison.OrdinalIgnoreCase))
    {
        _settingsService.AuthAccessToken = string.Empty;
        _settingsService.AuthIdToken = string.Empty;
        IsLogin = false;
        LoginUrl = _identityService.CreateAuthorizationRequest();
    }
    else if (unescapedUrl.Contains(GlobalSetting.Instance.Callback, StringComparison.OrdinalIgnoreCase))
    {
        var authResponse = new AuthorizeResponse(url);
        if (!string.IsNullOrWhiteSpace(authResponse.Code))
        {
            var userToken = await _identityService.GetTokenAsync(authResponse.Code);
            string accessToken = userToken.AccessToken;

            if (!string.IsNullOrWhiteSpace(accessToken))
            {
                _settingsService.AuthAccessToken = accessToken;
                _settingsService.AuthIdToken = authResponse.IdentityToken;
                await NavigationService.NavigateToAsync("//Main/Catalog");
            }
        }
    }
}

이 메서드는 반환 URI에 포함된 인증 응답을 구문 분석하고 유효한 인증 코드가 있는 경우 IdentityServer의 토큰 엔드포인트에 요청하여 인증 코드, PKCE 비밀 검증 도구 및 기타 필수 매개 변수를 전달합니다. 토큰 엔드포인트는 사용자 설정으로 노출되는 기본 엔드포인트의 포트 5105에서 /connect/token에 위치합니다. 사용자 설정에 관한 자세한 내용은 구성 관리를 참조하세요.

반환 URI의 유효성을 검사해야 합니다. eShopOnContainers 다중 플랫폼 앱은 반환 URI의 유효성을 검사하지 않지만, 오픈 리디렉션 공격을 방지하기 위해 반환 URI가 알려진 위치를 참조하는지 확인하는 것이 가장 좋습니다.

토큰 엔드포인트는 유효한 인증 코드 및 PKCE 비밀 검증 도구를 수신하면 액세스 토큰, ID 토큰 및 새로 고침 토큰으로 응답합니다. 액세스 토큰(API 리소스에 대한 액세스를 허용)과 ID 토큰은 애플리케이션 설정으로 저장되며 페이지 탐색을 수행합니다. 따라서 eShopOnContainers 다중 플랫폼 앱의 전반적인 효과는 다음과 같습니다. 사용자는 IdentityServer를 사용하여 인증에 성공할 수 있는 경우 //Main/Catalog 경로를 탐색합니다. 이 경로는 CatalogView를 선택한 탭으로 표시하는 TabbedPage입니다.

탐색에 관한 자세한 내용은 탐색을 참조하세요. WebView 탐색으로 인해 뷰 모델 메서드가 실행되는 과정에 관한 자세한 내용은 동작을 사용하여 탐색 호출을 참조하세요. 애플리케이션 설정에 관한 자세한 내용은 구성 관리를 참조하세요.

참고

eShopOnContainers는 앱이 SettingsView에서 모의 서비스를 사용하도록 구성된 경우에도 모의 로그인을 허용합니다. 이 모드에서는 앱이 IdentityServer와 통신하지 않으며, 그 대신 사용자가 자격 증명을 사용하여 로그인할 수 있도록 허용합니다.

로그아웃

사용자가 ProfileViewLOG OUT 단추를 탭하면 ProfileViewModel 클래스의 LogoutCommand가 실행되어 LogoutAsync 메서드가 실행됩니다. 이 메서드는 LoginView 페이지로 탐색을 수행하여 true로 설정된 LogoutParameter 인스턴스를 매개 변수로 전달합니다.

하나의 뷰가 생성되어 이를 탐색하면 해당 뷰의 연결된 뷰 모델의 InitializeAsync 메서드가 실행되며, 다음 코드 예제에서 보는 것과 같은 LoginViewModel 클래스의 Logout 메서드를 실행합니다.

private void Logout()
{
    var authIdToken = Settings.AuthIdToken;
    var logoutRequest = _identityService.CreateLogoutRequest(authIdToken);

    if (!string.IsNullOrEmpty(logoutRequest))
    {
        // Logout
        LoginUrl = logoutRequest;
    }
    
    // Omitted for brevity
}

이 메서드는 IdentityService 클래스에서 CreateLogoutRequest 메서드를 호출하여 애플리케이션 설정에서 검색된 ID 토큰을 매개 변수로 전달합니다. 애플리케이션 설정에 관한 자세한 내용은 구성 관리를 참조하세요. 다음 코드 예제는 CreateLogoutRequest 메서드를 보여줍니다.

public string CreateLogoutRequest(string token)
{
    // Omitted for brevity

    var (endpoint, callback) =
        (GlobalSetting.Instance.LogoutEndpoint, GlobalSetting.Instance.LogoutCallback);

    return $"{endpoint}?id_token_hint={token}&post_logout_redirect_uri={callback}";
}

이 메서드는 필수 매개 변수를 사용하여 IdentityServer의 최종 세션 엔드포인트에 대한 URI를 만듭니다. 최종 세션 엔드포인트는 사용자 설정으로 노출되는 기본 엔드포인트의 포트 5105에서 /connect/endsession에 위치합니다.

반환된 URI는 LoginViewModel 클래스의 LoginUrl 속성에 저장됩니다. IsLogin 속성은 true이지만 LoginViewWebView가 표시됩니다. WebView 데이터는 LoginUrl 속성이 IdentityServer의 최종 세션 엔드포인트로 설정된 경우 해당 Source 속성을 LoginViewModel 클래스의 LoginUrl 속성에 바인딩하며 IdentityServer에 로그아웃을 요청합니다. 로그아웃은 사용자가 로그인한 경우 IdentityServer가 이 요청을 수신할 때 발생합니다. 인증은 ASP.NET Core의 쿠키 인증 미들웨어에서 관리하는 쿠키로 추적됩니다. 따라서 IdentityServer에서 로그아웃하면 인증 쿠키가 제거되며 로그아웃 후 리디렉션 URI가 클라이언트로 다시 전송됩니다.

WebView는 다중 플랫폼 앱에서 로그아웃 후 리디렉션 URI로 리디렉션됩니다. 이 WebView 탐색을 수행하면 다음 코드 예제와 같이 LoginViewModel 클래스의 NavigateAsync 메서드가 실행됩니다.

private async Task NavigateAsync(string url)
{
    var unescapedUrl = System.Net.WebUtility.UrlDecode(url);

    if (unescapedUrl.Equals(GlobalSetting.Instance.LogoutCallback, StringComparison.OrdinalIgnoreCase))
    {
        _settingsService.AuthAccessToken = string.Empty;
        _settingsService.AuthIdToken = string.Empty;
        IsLogin = false;
        LoginUrl = _identityService.CreateAuthorizationRequest();
    }
    
    // Omitted for brevity
}

이 메서드는 애플리케이션 설정에서 ID 토큰과 액세스 토큰을 모두 지웁니다. IsLogin 속성을 false로 설정하여 LoginView 페이지의 WebView가 보이지 않게 합니다. 마지막으로, LoginUrl 속성은 사용자가 다음에 로그인을 시작할 때를 준비하기 위해 필요한 매개 변수를 사용하여 IdentityServer의 권한 부여 엔드포인트의 URI로 설정됩니다.

탐색에 관한 자세한 내용은 탐색을 참조하세요. WebView 탐색으로 인해 뷰 모델 메서드가 실행되는 과정에 관한 자세한 내용은 동작을 사용하여 탐색 호출을 참조하세요. 애플리케이션 설정에 관한 자세한 내용은 구성 관리를 참조하세요.

참고

eShopOnContainers는 앱이 SettingsView에서 모의 서비스를 사용하도록 구성된 경우에도 모의 로그아웃을 허용합니다. 이 모드에서는 앱이 IdentityServer와 통신하지 않고 그 대신 애플리케이션 설정에서 저장된 토큰을 지웁니다.

권한 부여

인증 후 ASP.NET Core 웹 API는 액세스 권한을 부여해야 하는 경우가 많으며, 이를 통해 서비스는 모든 사용자가 아닌 일부 인증된 사용자에게 API를 제공합니다.

다음 코드 예제와 같이 컨트롤러 또는 작업에 대한 액세스 권한을 인증된 사용자에게만 부여하는 Authorize 특성을 컨트롤러 또는 작업에 적용하여 ASP.NET Core 경로에 대한 액세스를 제한할 수 있습니다.

[Authorize]
public sealed class BasketController : Controller
{
    // Omitted for brevity
}

권한이 없는 사용자가 Authorize 특성으로 표시된 컨트롤러 또는 작업에 액세스하려고 하면 API 프레임워크는 401 (unauthorized) HTTP 상태 코드를 반환합니다.

참고

API를 특정 사용자에게만 제공하기 위해 Authorize 특성에 매개 변수를 지정할 수 있습니다. 자세한 내용은 ASP.NET Core 문서: 권한 부여를 참조하세요.

IdentityServer를 권한 부여 워크플로에 통합하면 그것이 제공하는 액세스 토큰이 권한 부여를 제어합니다. 이 방법은 아래 다이어그램에 나와 있습니다.

Authorization by access token.

eShopOnContainers 다중 플랫폼 앱은 ID 마이크로 서비스와 통신하고 인증 프로세스의 일부로 액세스 토큰을 요청합니다. 그런 다음 액세스 토큰은 액세스 요청의 일부로서 주문 및 basket 마이크로 서비스에 의해 노출되는 API에 전달됩니다. 액세스 토큰에는 클라이언트 및 사용자에 관한 정보가 포함됩니다. 그런 다음, API는 해당 정보를 사용하여 데이터에 대한 액세스 권한을 부여합니다. API를 보호하도록 IdentityServer를 구성하는 방법에 관한 자세한 내용은 API 리소스 구성을 참조하세요.

권한 부여를 수행하도록 IdentityServer를 구성

IdentityServer를 사용하여 권한 부여를 수행하려면 해당 권한 부여 미들웨어를 웹 애플리케이션의 HTTP 요청 파이프라인에 추가해야 합니다. 미들웨어는 Configure 메서드에서 호출되는 웹 애플리케이션의 Startup 클래스 내 ConfigureAuth 메서드에 추가되며, eShopOnContainers 참조 애플리케이션의 다음 코드 예제에 설명되어 있습니다.

protected virtual void ConfigureAuth(IApplicationBuilder app)
{
    var identityUrl = Configuration.GetValue<string>("IdentityUrl");
    app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
    {
        Authority = identityUrl.ToString(),
        ScopeName = "basket",
        RequireHttpsMetadata = false,
    });
}

이 메서드는 유효한 액세스 토큰으로만 API에 액세스할 수 있도록 합니다. 미들웨어는 들어오는 토큰의 유효성을 검사하여 신뢰할 수 있는 발급자로부터 전송되었는지 확인하고 토큰을 수신하는 API와 함께 사용할 수 있는지 확인합니다. 따라서 주문 또는 basket 컨트롤러로 검색하면 액세스 토큰이 필요함을 나타내는 401 (unauthorized) HTTP 상태 코드가 반환됩니다.

참고

IdentityServer의 권한 부여 미들웨어는 MVC를 추가하기 전에 app.UseMvc() 또는 app.UseMvcWithDefaultRoute()를 사용하여 웹 애플리케이션의 HTTP 요청 파이프라인에 추가해야 합니다.

API에 대한 액세스 요청 수행

주문 및 basket 마이크로 서비스를 요청할 때 다음 코드 예제와 같이 인증 프로세스 중에 IdentityServer에서 가져온 액세스 토큰을 요청에 포함해야 합니다.

var authToken = Settings.AuthAccessToken;
Order = await _ordersService.GetOrderAsync(order.OrderNumber, authToken);

액세스 토큰은 애플리케이션 설정으로 저장되고 플랫폼별 스토리지에서 검색되며 OrderService 클래스의 GetOrderAsync 메서드 호출에 포함됩니다.

마찬가지로 다음 코드 예제와 같이 IdentityServer로 보호된 API로 데이터를 보낼 때 액세스 토큰을 포함해야 합니다.

var authToken = Settings.AuthAccessToken;
await _basketService.UpdateBasketAsync(
    new CustomerBasket
    {
        BuyerId = userInfo.UserId, 
        Items = BasketItems.ToList()
    }, 
    authToken);

액세스 토큰은 설정에서 검색되고 BasketService 클래스의 UpdateBasketAsync 메서드 호출에 포함됩니다.

eShopOnContainers 다중 플랫폼 앱의 RequestProvider 클래스는 HttpClient 클래스를 사용하여 eShopOnContainers 참조 애플리케이션에서 노출하는 RESTful API에 대한 요청을 수행합니다. 권한 부여가 필요한 주문 및 basket API를 요청할 때 유효한 액세스 토큰을 요청에 포함해야 합니다. 이는 다음 코드 예제에 설명된 대로 HttpClient 인스턴스의 헤더에 액세스 토큰을 추가하여 수행합니다.

httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

HttpClient 클래스의 DefaultRequestHeaders 속성은 각 요청과 함께 전송되는 헤더를 노출하며, 액세스 토큰은 Bearer를 문자열의 접두사로 하는 Authorization 헤더에 추가됩니다. 요청이 RESTful API로 전송되면 Authorization 헤더의 값이 추출되며, 그 값을 신뢰할 수 있는 발급자에게서 전송하여 사용자가 이를 수신하는 API를 호출할 수 있는 권한이 있는지 여부를 확인하는 데 사용하도록 유효성 검사가 진행됩니다.

eShopOnContainers 다중 플랫폼 앱이 웹 요청을 수행하는 방법에 관한 자세한 내용은 원격 데이터 액세스를 참조하세요.

요약

ASP.NET 웹 애플리케이션과 통신하는 .NET MAUI 앱에 인증 및 권한 부여를 통합하는 방법에는 여러 가지가 있습니다. eShopOnContainers 다중 플랫폼 앱은 IdentityServer 4를 사용하는 컨테이너화된 ID 마이크로 서비스를 사용하여 인증 및 권한 부여를 수행합니다. IdentityServer는 전달자 토큰 인증을 수행하기 위해 ASP.NET Core ID와 통합되는 ASP.NET Core에 대한 오픈 소스 OpenID Connect 및 OAuth 2.0 프레임워크입니다.

다중 플랫폼 앱은 IdentityServer에서 보안 토큰을 요청하여 사용자를 인증하거나 리소스에 액세스합니다. 리소스에 액세스할 때 권한 부여가 필요한 API에 대한 요청에 액세스 토큰을 포함해야 합니다. IdentityServer의 미들웨어는 들어오는 액세스 토큰의 유효성을 검사하여 신뢰할 수 있는 발급자에게서 전송되고 이를 수신하는 API와 함께 사용할 수 있는지 확인합니다.