Azure Active Directory B2C를 사용하여 호스트된 ASP.NET Core Blazor WebAssembly 앱 보호

이 문서에서는 인증을 위해 AAD(Azure Active Directory) B2C를 사용하는 호스트된 Blazor WebAssembly 솔루션을 만드는 방법을 설명합니다.

솔루션에 대한 자세한 내용은 ASP.NET Core Blazor용 도구를 참조하세요.

AAD B2C에 앱을 등록하고 솔루션 만들기

테넌트 만들기

자습서: Azure Active Directory B2C 테넌트 만들기의 지침에 따라 AAD B2C 테넌트를 만듭니다. 사용할 테넌트를 만들거나 식별한 직후 이 문서로 돌아옵니다.

AAD B2C 인스턴스를 기록해 둡니다(예: 후행 슬래시를 포함하는 https://contoso.b2clogin.com/). 이 인스턴스는 Azure B2C 앱 등록의 스키마 및 호스트로, Azure Portal의 앱 등록 페이지에서 엔드포인트 창을 열어 찾을 수 있습니다.

서버 API 앱 등록

서버 API 앱을 위한 AAD B2C 앱을 등록합니다.

  1. Azure Portal에서 Azure Active Directory로 이동합니다. 사이드바에서 앱 등록을 선택합니다. 새 등록 단추를 선택합니다.
  2. 앱의 이름을 지정합니다(예: Blazor Server AAD B2C).
  3. 지원되는 계정 유형으로 다중 테넌트 옵션 모든 ID 공급자 또는 조직 디렉터리의 계정(사용자 흐름을 사용하여 사용자를 인증하는 경우)
  4. 이 시나리오에서는 ‘서버 API 앱’에 리디렉션 URI가 필요하지 않으므로 드롭다운이 으로 설정된 상태로 두고 리디렉션 URI를 입력하지 않습니다.
  5. 확인되지 않은 게시자 도메인을 사용하는 경우 권한>openid 및 offline_access 권한에 대한 관리자 동의 허용을 선택 취소했는지 확인합니다. 게시자 도메인이 확인된 경우에는 이 확인란이 표시되지 않습니다.
  6. 등록을 선택합니다.

다음과 같은 정보를 기록해 둡니다.

  • 서버 API 앱 애플리케이션(클라이언트) ID(예: 41451fa7-82d9-4673-8fa5-69eff5a761fd)
  • AAD 주/게시자/테넌트 도메인(예: contoso.onmicrosoft.com): 도메인은 Azure Portal에서 등록된 앱의 브랜딩 블레이드에 게시자 도메인으로 표시되어 있습니다.

API 표시에서:

  1. 범위 추가를 선택합니다.
  2. 저장 및 계속을 선택합니다.
  3. 범위 이름을 지정합니다(예: API.Access).
  4. 관리자 동의 표시 이름을 지정합니다(예: Access API).
  5. 관리자 동의 설명을 지정합니다(예: Allows the app to access server app API endpoints.).
  6. 상태사용으로 설정되었는지 확인합니다.
  7. 범위 추가를 선택합니다.

다음과 같은 정보를 기록해 둡니다.

  • 앱 ID URI(예: api://41451fa7-82d9-4673-8fa5-69eff5a761fd, https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd 또는 사용자가 지정한 사용자 지정 값)
  • 범위 이름(예: API.Access)

클라이언트 앱 등록

클라이언트 앱을 위한 AAD B2C 앱을 등록합니다.

  1. Azure Portal에서 Azure Active Directory로 이동합니다. 사이드바에서 앱 등록을 선택합니다. 새 등록 단추를 선택합니다.
  2. 앱의 이름을 지정합니다(예: Blazor 클라이언트 AAD B2C).
  3. 지원되는 계정 유형으로 다중 테넌트 옵션 모든 ID 공급자 또는 조직 디렉터리의 계정(사용자 흐름을 사용하여 사용자를 인증하는 경우)
  4. 리디렉션 URI 드롭다운은 SPA(단일 페이지 애플리케이션) 으로 설정하고 리디렉션 URI를 https://localhost/authentication/login-callback으로 지정합니다. Azure 기본 호스트에 대한 프로덕션 리디렉션 URI(예: azurewebsites.net) 또는 사용자 지정 도메인 호스트(예: contoso.com)를 알고 있는 경우 localhost 리디렉션 URI를 제공하는 동시에 프로덕션 리디렉션 URI를 추가할 수도 있습니다. 추가하는 프로덕션 리디렉션 URI에 비 :443 포트에 대한 포트 번호를 포함해야 합니다.
  5. 확인되지 않은 게시자 도메인을 사용하는 경우 권한>openid 및 offline_access 권한에 대한 관리자 동의 허용을 선택 취소했는지 확인합니다. 게시자 도메인이 확인된 경우에는 이 확인란이 표시되지 않습니다.
  6. 등록을 선택합니다.

참고

localhost AAD B2C 리디렉션 URI에 대한 포트 번호를 제공할 필요는 없습니다. 자세한 내용은 Redirect URI(회신 URL) 제한 사항: Localhost 예외(Azure 설명서)를 참조하세요.

애플리케이션(클라이언트) ID를 기록해 둡니다(예: 4369008b-21fa-427c-abaa-9b53bf58e538).

인증>플랫폼 구성>SPA(단일 페이지 애플리케이션)에서 다음을 수행합니다.

  1. https://localhost/authentication/login-callback리디렉션 URI가 있는지 확인합니다.
  2. 암시적 허용 섹션에서 액세스 토큰ID 토큰의 확인란을 선택 해제 상태로 유지합니다.
  3. 이 환경에서는 앱의 나머지 기본값을 그대로 사용해도 좋습니다.
  4. 저장 단추를 선택합니다.

API 사용 권한에서:

  1. 사용 권한 추가를 선택하고 내 API를 선택합니다.
  2. 이름 열에서 ‘서버 API 앱’을 선택합니다(예: Blazor Server AAD B2C).
  3. API 목록을 엽니다.
  4. API에 대한 액세스를 사용하도록 설정합니다(예: API.Access).
  5. 권한 추가를 선택합니다.
  6. {테넌트 이름}에 대한 관리자 동의 허용 단추를 선택합니다. 를 선택하여 확인합니다.

중요

앱 사용에 대한 동의가 사용자에게 위임되므로 API 권한 구성의 마지막 단계에서 테넌트에 관리자 동의를 부여할 권한이 없는 경우 다음 추가 단계를 수행해야 합니다.

  • 앱은 신뢰할 수 있는 게시자 도메인을 사용해야 합니다.
  • Azure Portal의 Server 앱 구성에서 API 공개를 선택합니다. 권한 있는 클라이언트 애플리케이션에서 클라이언트 애플리케이션 추가 단추를 선택합니다. Client 앱의 애플리케이션(클라이언트) ID를 추가합니다(예: 4369008b-21fa-427c-abaa-9b53bf58e538).

Home>Azure AD B2C>사용자 흐름에서 다음을 수행합니다.

가입 및 로그인 사용자 흐름 만들기

최소한 애플리케이션 클레임>표시 이름 사용자 특성을 선택하여 LoginDisplay 구성 요소(Shared/LoginDisplay.razor)의 context.User.Identity.Name을 채웁니다.

앱에 대해 만들어진 가입 및 로그인 사용자 흐름 이름을 기록해 둡니다(예: B2C_1_signupsignin).

앱 만들기

다음 명령에서 자리 표시자를 앞에서 기록해 둔 정보로 바꾸고 명령 셸에서 명령을 실행합니다.

dotnet new blazorwasm -au IndividualB2C --aad-b2c-instance "{AAD B2C INSTANCE}" --api-client-id "{SERVER API APP CLIENT ID}" --app-id-uri "{SERVER API APP ID URI}" --client-id "{CLIENT APP CLIENT ID}" --default-scope "{DEFAULT SCOPE}" --domain "{TENANT DOMAIN}" -ho -o {APP NAME} -ssp "{SIGN UP OR SIGN IN POLICY}"

경고

OIDC 앱 식별자의 형성을 중단하는 대시(-)를 앱 이름 {APP NAME}에 사용하지 마세요. Blazor WebAssembly 프로젝트 템플릿의 논리는 솔루션 구성에서 OIDC 앱 식별자에 대해 프로젝트 이름을 사용합니다. 파스칼식 대/소문자(BlazorSample) 또는 밑줄(Blazor_Sample)은 사용 가능한 대안입니다. 자세한 내용은 호스트된 Blazor WebAssembly 프로젝트 이름의 대시가 OIDC 보안 중단(dotnet/aspnetcore #35337)을 참조하세요.

자리표시자 Azure Portal 이름 예제
{AAD B2C INSTANCE} 인스턴스 https://contoso.b2clogin.com/(후행 슬래시 포함)
{APP NAME} BlazorSample
{CLIENT APP CLIENT ID} Client 앱의 애플리케이션(클라이언트) ID 4369008b-21fa-427c-abaa-9b53bf58e538
{DEFAULT SCOPE} 범위 이름 API.Access
{SERVER API APP CLIENT ID} 서버 API 앱의 애플리케이션(클라이언트) ID 41451fa7-82d9-4673-8fa5-69eff5a761fd
{SERVER API APP ID URI} 애플리케이션 ID URI† 41451fa7-82d9-4673-8fa5-69eff5a761fd
{SIGN UP OR SIGN IN POLICY} 가입/로그인 사용자 흐름 B2C_1_signupsignin1
{TENANT DOMAIN} 주/게시자/테넌트 도메인 contoso.onmicrosoft.com

†Blazor WebAssembly 템플릿은 dotnet new 명령에 전달된 앱 ID URI 인수에 api://의 구성표를 자동으로 추가합니다. {SERVER API APP ID URI} 자리 표시자의 앱 ID URI를 제공할 때 구성표가 api://인 경우 앞의 테이블에 나온 것처럼 인수에서 구성표(api://)를 제거하세요. 앱 ID URI가 사용자 지정 값이거나 다른 구성표(예를 들어 https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd와 유사한 확인되지 않은 게시자 도메인에 대해 https://)를 갖는 경우 기본 범위 URI를 수동으로 업데이트하고 템플릿이 Client 앱을 만든 후 api:// 구성표를 제거해야 합니다. 자세한 내용은 액세스 토큰 범위 섹션의 참고를 참조하세요. 이러한 시나리오를 해결하기 위해 ASP.NET Core의 이후 릴리스에서 Blazor WebAssembly 템플릿이 변경될 수 있습니다. 자세한 내용은 Double scheme for App ID URI with Blazor WASM template (hosted, single org) (dotnet/aspnetcore #27417)을 참조하세요.

-o|--output 옵션으로 지정된 출력 위치는 프로젝트 폴더가 없는 경우 폴더를 하나 만들고 앱 이름의 일부가 됩니다. OIDC 앱 식별자의 형성을 중단하는 대시(-)를 앱 이름에 사용하지 마세요(앞에 나온 경고 참조).

참고

Blazor WebAssembly 프로젝트 템플릿에서 호스티된 Blazor WebAssembly 솔루션에 설정한 범위에서는 앱 ID URI 호스트가 반복될 수 있습니다. Client 앱의 Program.cs에서 DefaultAccessTokenScopes 컬렉션에 대해 구성된 범위가 올바른지 확인합니다.

Server 앱 구성

이 섹션은 솔루션의 Server 앱에 적용됩니다.

인증 패키지

Microsoft Identity 플랫폼을 통한 ASP.NET Core Web API에 대한 호출의 권한 부여 및 인증 지원은 Microsoft.Identity.Web 패키지에서 제공합니다.

참고

.NET 앱에 패키지를 추가하는 지침은 패키지 사용 워크플로(NuGet 설명서)에서 패키지 설치 및 관리 아래의 문서를 참조하세요. NuGet.org에서 올바른 패키지 버전을 확인합니다.

Blazor WebAssembly 템플릿에서 만든 호스트된 Blazor 솔루션의 Server 앱에는 기본적으로 Microsoft.Identity.Web.UI 패키지가 포함됩니다. 패키지는 웹앱에서 사용자 인증을 위한 UI를 추가하며 Blazor 프레임워크에서 사용되지 않습니다. Server 앱을 사용하여 사용자를 직접 인증하지 않는 경우 Server 앱의 프로젝트 파일에서 패키지 참조를 제거하는 것이 안전합니다.

인증 서비스 지원

AddAuthentication 메서드는 앱 내에서 인증 서비스를 설정하고 JWT 전달자 처리기를 기본 인증 메서드로 구성합니다. AddMicrosoftIdentityWebApi 메서드는 Microsoft Identity 플랫폼 v2.0을 사용하여 웹 API를 보호하도록 서비스를 구성합니다. 이 메서드에는 인증 옵션을 초기화하는 데 필요한 설정을 포함하는 앱 구성의 AzureAdB2C 섹션이 필요합니다.

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAdB2C"));

UseAuthenticationUseAuthorization은 다음을 수행합니다.

  • 앱이 수신 요청에 대해 토큰의 구문 분석 및 유효성 검사를 시도하도록 합니다.
  • 올바른 자격 증명 없이 보호된 리소스에 액세스하려는 요청은 모두 실패하도록 합니다.
app.UseAuthentication();
app.UseAuthorization();

User.Identity.Name

기본적으로 User.Identity.Name은 채워지지 않습니다.

name 클레임 유형에서 값을 받도록 앱을 구성하려면 다음을 수행합니다.

앱 설정

appsettings.json 파일은 액세스 토큰의 유효성을 검사하는 데 사용되는 JWT 전달자 처리기를 구성하기 위한 옵션을 포함합니다.

{
  "AzureAdB2C": {
    "Instance": "https://{TENANT}.b2clogin.com/",
    "ClientId": "{SERVER API APP CLIENT ID}",
    "Domain": "{TENANT DOMAIN}",
    "SignUpSignInPolicyId": "{SIGN UP OR SIGN IN POLICY}"
  }
}

예:

{
  "AzureAdB2C": {
    "Instance": "https://contoso.b2clogin.com/",
    "ClientId": "41451fa7-82d9-4673-8fa5-69eff5a761fd",
    "Domain": "contoso.onmicrosoft.com",
    "SignUpSignInPolicyId": "B2C_1_signupsignin1",
  }
}

WeatherForecast 컨트롤러

WeatherForecast 컨트롤러(Controllers/WeatherForecastController.cs)는 컨트롤러에 적용된 [Authorize] 특성으로 보호된 API를 노출합니다. 다음과 같은 사항을 이해하는 것이 중요합니다.

  • 이 API 컨트롤러의 [Authorize] 특성은 무단 액세스로부터 이 API를 보호하는 유일한 항목입니다.
  • Blazor WebAssembly 앱에서 사용되는 [Authorize] 특성은 앱이 올바르게 작동하려면 사용자에게 권한이 부여되어야 한다는 힌트로만 앱에 제공됩니다.
[Authorize]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    [HttpGet]
    public IEnumerable<WeatherForecast> Get()
    {
        ...
    }
}

Client 앱 구성

이 섹션은 솔루션의 Client 앱에 적용됩니다.

인증 패키지

앱이 개별 B2C 계정을 사용하도록 만들어진 경우(IndividualB2C) 해당 앱은 자동으로 Microsoft 인증 라이브러리(Microsoft.Authentication.WebAssembly.Msal)에 대한 패키지 참조를 받습니다. 패키지는 앱이 사용자를 인증하고 보호된 API를 호출하는 데 사용할 토큰을 가져올 수 있도록 지원하는 기본 형식 세트를 제공합니다.

앱에 인증을 추가하는 경우에는 Microsoft.Authentication.WebAssembly.Msal 패키지를 앱에 수동으로 추가합니다.

참고

.NET 앱에 패키지를 추가하는 지침은 패키지 사용 워크플로(NuGet 설명서)에서 패키지 설치 및 관리 아래의 문서를 참조하세요. NuGet.org에서 올바른 패키지 버전을 확인합니다.

Microsoft.Authentication.WebAssembly.Msal 패키지는 타동적으로 Microsoft.AspNetCore.Components.WebAssembly.Authentication 패키지를 앱에 추가합니다.

인증 서비스 지원

서버 프로젝트로 요청을 전송할 때 액세스 토큰을 포함하는 HttpClient 인스턴스에 대한 지원이 추가됩니다.

Program.cs:

builder.Services.AddHttpClient("{APP ASSEMBLY}.ServerAPI", client => 
    client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
    .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();

builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>()
    .CreateClient("{APP ASSEMBLY}.ServerAPI"));

자리 표시자 {APP ASSEMBLY}는 앱의 어셈블리 이름입니다(예: BlazorSample.Client).

사용자 인증에 대한 지원은 Microsoft.Authentication.WebAssembly.Msal 패키지에서 제공하는 AddMsalAuthentication 확장 메서드를 통해 서비스 컨테이너에 등록됩니다. 이 메서드는 앱이 IP(Identity 공급자)와 상호 작용하는 데 필요한 서비스를 설정합니다.

Program.cs:

builder.Services.AddMsalAuthentication(options =>
{
    builder.Configuration.Bind("AzureAdB2C", options.ProviderOptions.Authentication);
    options.ProviderOptions.DefaultAccessTokenScopes.Add("{SCOPE URI}");
});

AddMsalAuthentication 메서드는 콜백을 받아서 앱을 인증하는 데 필요한 매개 변수를 구성합니다. 앱을 구성하는 데 필요한 값은 앱을 등록할 때 Azure Portal AAD 구성에서 얻을 수 있습니다.

구성은 wwwroot/appsettings.json 파일에서 제공합니다.

{
  "AzureAdB2C": {
    "Authority": "{AAD B2C INSTANCE}{TENANT DOMAIN}/{SIGN UP OR SIGN IN POLICY}",
    "ClientId": "{CLIENT APP CLIENT ID}",
    "ValidateAuthority": false
  }
}

위의 구성에서는 {AAD B2C INSTANCE}에 후행 슬래시가 포함됩니다.

예:

{
  "AzureAdB2C": {
    "Authority": "https://contoso.b2clogin.com/contoso.onmicrosoft.com/B2C_1_signupsignin1",
    "ClientId": "4369008b-21fa-427c-abaa-9b53bf58e538",
    "ValidateAuthority": false
  }
}

액세스 토큰 범위

기본 액세스 토큰 범위는 다음과 같은 액세스 토큰 범위 목록을 나타냅니다.

  • 기본적으로 로그인 요청에 포함되어 있음.
  • 인증 직후에 액세스 토큰을 프로비저닝하는 데 사용됨.

모든 범위는 Azure Active Directory 규칙에 따라 동일한 앱에 속해 있어야 합니다. 필요에 따라 추가 API 앱에 대한 추가 범위가 추가될 수 있습니다.

builder.Services.AddMsalAuthentication(options =>
{
    ...
    options.ProviderOptions.DefaultAccessTokenScopes.Add("{SCOPE URI}");
});

참고

Blazor WebAssembly 템플릿은 dotnet new 명령에 전달된 앱 ID URI 인수에 api://의 구성표를 자동으로 추가합니다. Blazor 프로젝트 템플릿에서 앱을 생성할 때 기본 액세스 토큰 범위의 값이 Azure Portal에 제공한 올바른 사용자 지정 앱 ID URI 값 또는 다음 형식 중 하나인 값을 사용하는지 확인합니다.

  • 디렉터리의 게시자 도메인을 신뢰할 수 있는 경우 기본 액세스 토큰 범위는 일반적으로 다음 예제와 비슷한 값입니다. 여기서 API.Access는 기본 범위 이름입니다.

    options.ProviderOptions.DefaultAccessTokenScopes.Add(
        "api://41451fa7-82d9-4673-8fa5-69eff5a761fd/API.Access");
    

    이중 구성표(api://api://...)의 값을 검사합니다. 이중 구성표가 있는 경우 값에서 첫 번째 api:// 구성표를 제거합니다.

  • 디렉터리의 게시자 도메인을 신뢰할 수 없는 경우 기본 액세스 토큰 범위는 일반적으로 다음 예제와 비슷한 값입니다. 여기서 API.Access는 기본 범위 이름입니다.

    options.ProviderOptions.DefaultAccessTokenScopes.Add(
        "https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd/API.Access");
    

    추가 api:// 구성표(api://https://contoso.onmicrosoft.com/...)의 값을 검사합니다. 추가 api:// 구성표가 있는 경우 값에서 api:// 구성표를 제거합니다.

이러한 시나리오를 해결하기 위해 ASP.NET Core의 이후 릴리스에서 Blazor WebAssembly 템플릿이 변경될 수 있습니다. 자세한 내용은 Double scheme for App ID URI with Blazor WASM template (hosted, single org) (dotnet/aspnetcore #27417)을 참조하세요.

AdditionalScopesToConsent를 사용하여 추가 범위를 지정합니다.

options.ProviderOptions.AdditionalScopesToConsent.Add("{ADDITIONAL SCOPE URI}");

자세한 내용은 ‘추가 시나리오’ 문서의 다음 섹션을 참조하세요.

로그인 모드

프레임워크는 기본적으로 팝업 로그인 모드로 설정되며 팝업을 열 수 없는 경우 리디렉션 로그인 모드로 대체됩니다. MsalProviderOptionsLoginMode 속성을 redirect로 설정하여 리디렉션 로그인 모드를 사용하도록 MSAL을 구성합니다.

builder.Services.AddMsalAuthentication(options =>
{
    ...
    options.ProviderOptions.LoginMode = "redirect";
});

기본 설정은 popup이며 문자열 값은 대/소문자를 구분하지 않습니다.

Imports 파일

Microsoft.AspNetCore.Components.Authorization 네임스페이스는 _Imports.razor 파일을 통해 앱 전체에서 사용할 수 있게 됩니다.

@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Microsoft.JSInterop
@using {APPLICATION ASSEMBLY}.Client
@using {APPLICATION ASSEMBLY}.Client.Shared

인덱스 페이지

인덱스 페이지(wwwroot/index.html)는 JavaScript로 AuthenticationService를 정의하는 스크립트를 포함합니다. AuthenticationService는 OIDC 프로토콜의 하위 수준 세부 정보를 처리합니다. 앱은 내부적으로 스크립트에 정의된 메서드를 호출하여 인증 작업을 수행합니다.

<script src="_content/Microsoft.Authentication.WebAssembly.Msal/AuthenticationService.js"></script>

App 구성 요소

App 구성 요소(App.razor)는 Blazor Server 앱에 있는 App 구성 요소와 비슷합니다.

  • CascadingAuthenticationState 구성 요소는 앱의 나머지 부분에 AuthenticationState를 노출하는 것을 관리합니다.
  • AuthorizeRouteView 구성 요소는 현재 사용자가 지정된 페이지에 액세스할 수 있는 권한이 부여받았는지 확인하고 그러지 않은 경우 RedirectToLogin 구성 요소를 렌더링합니다.
  • RedirectToLogin 구성 요소는 권한 없는 사용자를 로그인 페이지로 리디렉션하는 기능을 관리합니다.

ASP.NET Core 릴리스 간 프레임워크 변경으로 인해 App 구성 요소의 Razor 변경 내용(App.razor)은 이 섹션에 표시되지 않습니다. 지정된 릴리스의 구성 요소의 변경 내용을 검사하려면 다음 방법 중 하나를 사용합니다.

  • 사용하려는 ASP.NET Core 버전의 기본 Blazor WebAssembly 프로젝트 템플릿에서 인증을 위해 프로비전된 앱을 만듭니다. 생성된 앱에서 App 구성 요소(App.razor)를 검사합니다.

  • 참조 소스에서 App 구성 요소(App.razor)를 검사합니다.

    참고

    .NET 참조 원본의 설명서 링크는 일반적으로 다음 릴리스의 .NET을 위한 현재 개발을 나타내는 리포지토리의 기본 분기를 로드합니다. 특정 릴리스를 위한 태그를 선택하려면 Switch branches or tags(분기 또는 태그 전환) 드롭다운 목록을 사용합니다. 자세한 내용은 ASP.NET Core 소스 코드(dotnet/AspNetCore.Docs #26205)의 버전 태그를 선택하는 방법을 참조하세요.

RedirectToLogin 구성 요소

RedirectToLogin 구성 요소(Shared/RedirectToLogin.razor)는 다음을 수행합니다.

  • 로그인 페이지로의 권한 없는 사용자 리디렉션을 관리합니다.
  • 사용자가 인증에 성공하면 해당 페이지로 되돌아올 수 있도록 사용자가 액세스하려고 하는 현재 URL을 유지합니다.
@inject NavigationManager Navigation
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@code {
    protected override void OnInitialized()
    {
        Navigation.NavigateTo(
            $"authentication/login?returnUrl={Uri.EscapeDataString(Navigation.Uri)}");
    }
}

LoginDisplay 구성 요소

LoginDisplay 구성 요소(Shared/LoginDisplay.razor)는 MainLayout 구성 요소(Shared/MainLayout.razor)에서 렌더링되고 다음 동작을 관리합니다.

  • 인증된 사용자의 경우:
    • 현재 사용자 이름을 표시합니다.
    • 앱에서 로그아웃하는 단추를 제공합니다.
  • 익명 사용자의 경우, 로그인 옵션을 제공합니다.
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject NavigationManager Navigation
@inject SignOutSessionStateManager SignOutManager

<AuthorizeView>
    <Authorized>
        Hello, @context.User.Identity.Name!
        <button class="nav-link btn btn-link" @onclick="BeginLogout">
            Log out
        </button>
    </Authorized>
    <NotAuthorized>
        <a href="authentication/login">Log in</a>
    </NotAuthorized>
</AuthorizeView>

@code {
    private async Task BeginLogout(MouseEventArgs args)
    {
        await SignOutManager.SetSignOutState();
        Navigation.NavigateTo("authentication/logout");
    }
}

Authentication 구성 요소

Authentication 구성 요소에 의해 생성된 페이지(Pages/Authentication.razor)는 다른 인증 단계를 처리하는 데 필요한 경로를 정의합니다.

RemoteAuthenticatorView 구성 요소는 다음과 같습니다.

@page "/authentication/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication

<RemoteAuthenticatorView Action="@Action" />

@code {
    [Parameter]
    public string Action { get; set; }
}

FetchData 구성 요소

FetchData 구성 요소는 다음을 수행하는 방법을 보여 줍니다.

  • 액세스 토큰을 프로비저닝합니다.
  • 액세스 토큰을 사용하여 ‘서버’ 앱에서 보호된 리소스 API를 호출합니다.

@attribute [Authorize] 지시문은 사용자가 이 구성 요소에 액세스하기 위해 권한을 부여받아야 한다는 것을 Blazor WebAssembly 권한 부여 시스템에 나타냅니다. Client 앱에 특성이 있으면 서버에 있는 API가 적절한 자격 증명 없이 호출되는 것을 방지하지 않습니다. 또한 Server 앱은 적절한 엔드포인트에서 [Authorize]를 사용하여 올바로 보호해야 합니다.

IAccessTokenProvider.RequestAccessToken은 API를 호출하는 요청에 추가할 수 있는 액세스 토큰을 요청하는 작업을 처리합니다. 토큰이 캐시되었거나 서비스에서 사용자 개입 없이 새 액세스 토큰을 프로비저닝할 수 있으면 토큰 요청이 성공합니다. 그러지 않으면 토큰 요청이 실패하고 AccessTokenNotAvailableExceptiontry-catch 문에 catch됩니다.

요청에 포함할 실제 토큰을 가져오려면 앱에서 tokenResult.TryGetToken(out var token)을 호출하여 요청이 성공했는지 확인해야 합니다.

요청이 성공하면 토큰 변수가 액세스 토큰으로 채워집니다. 토큰의 AccessToken.Value 속성은 Authorization 요청 헤더에 포함할 리터럴 문자열을 노출합니다.

사용자 개입 없이 토큰을 프로비저닝할 수 없어 요청이 실패한 경우 토큰 결과에 리디렉션 URL이 포함됩니다. 이 URL로 이동하면 사용자가 로그인 페이지로 이동하고 인증 성공 후 현재 페이지로 돌아옵니다.

@page "/fetchdata"
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using {APP NAMESPACE}.Shared
@attribute [Authorize]
@inject HttpClient Http

...

@code {
    private WeatherForecast[] forecasts;

    protected override async Task OnInitializedAsync()
    {
        try
        {
            forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
    }
}

앱 실행

서버 프로젝트에서 앱을 실행합니다. Visual Studio를 사용하는 경우 다음 중 하나를 수행합니다.

  • 도구 모음의 시작 프로젝트 드롭다운 목록을 ‘서버 API 앱’으로 설정하고 실행 단추를 선택합니다.
  • 솔루션 탐색기에서 서버 프로젝트를 선택하고 도구 모음에서 실행 단추를 선택하거나 디버그 메뉴에서 앱을 시작합니다.

UserManagerSignInManager

서버 앱에 다음이 필요한 경우 사용자 ID 클레임 유형을 설정합니다.

ASP.NET Core 6.0 이상의 Program.cs에서 다음을 수행합니다.

using System.Security.Claims;

...

builder.Services.Configure<IdentityOptions>(options => 
    options.ClaimsIdentity.UserIdClaimType = ClaimTypes.NameIdentifier);

ASP.NET Core 6.0 이전 버전의 Startup.ConfigureServices에서:

using System.Security.Claims;

...

services.Configure<IdentityOptions>(options => 
    options.ClaimsIdentity.UserIdClaimType = ClaimTypes.NameIdentifier);

다음 WeatherForecastControllerGet 메서드가 호출될 때 UserName을 로깅합니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using BlazorSample.Server.Models;
using BlazorSample.Shared;

namespace BlazorSample.Server.Controllers
{
    [Authorize]
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        private readonly UserManager<ApplicationUser> userManager;

        private static readonly string[] Summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", 
            "Balmy", "Hot", "Sweltering", "Scorching"
        };

        private readonly ILogger<WeatherForecastController> logger;

        public WeatherForecastController(ILogger<WeatherForecastController> logger, 
            UserManager<ApplicationUser> userManager)
        {
            this.logger = logger;
            this.userManager = userManager;
        }

        [HttpGet]
        public async Task<IEnumerable<WeatherForecast>> Get()
        {
            var rng = new Random();

            var user = await userManager.GetUserAsync(User);

            if (user != null)
            {
                logger.LogInformation($"User.Identity.Name: {user.UserName}");
            }

            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = rng.Next(-20, 55),
                Summary = Summaries[rng.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }
}

이전 예제에서는 다음을 수행합니다.

  • Server 프로젝트의 네임스페이스는 BlazorSample.Server입니다.
  • Shared 프로젝트의 네임스페이스는 BlazorSample.Shared입니다.

사용자 지정 사용자 흐름

Microsoft 인증 라이브러리(Microsoft.Authentication.WebAssembly.Msal, NuGet 패키지)는 기본적으로 AAD B2C 사용자 흐름을 지원하지 않습니다. 개발자 코드에서 사용자 지정 사용자 흐름을 만듭니다.

사용자 지정 사용자 흐름의 챌린지를 작성하는 방법에 대한 자세한 내용은 Azure Active Directory B2C의 사용자 흐름을 참조하세요.

문제 해결

일반 오류

  • 앱 또는 IP(Identity 공급자)의 잘못된 구성

    가장 일반적인 오류는 잘못된 구성으로 인해 발생합니다. 다음은 몇 가지 예제입니다.

    • 시나리오의 요구 사항에 따라, 누락되거나 잘못된 권한, 인스턴스, 테넌트 ID, 테넌트 도메인, 클라이언트 ID 또는 리디렉션 URI 때문에 앱에서 클라이언트를 인증하지 못합니다.
    • 액세스 토큰 범위가 잘못되어 클라이언트가 서버 웹 API 엔드포인트에 액세스하지 못합니다.
    • 서버 API 권한이 잘못되거나 누락되어 클라이언트가 서버 웹 API 엔드포인트에 액세스할 수 없습니다.
    • Identity 공급자 앱 등록의 리디렉션 URI에 구성된 것과 다른 포트에서 앱을 실행합니다.

    이 문서 지침의 구성 섹션에서는 올바른 구성의 예를 보여 줍니다. 앱 및 IP 구성을 찾는 문서의 각 섹션을 주의 깊게 확인하세요.

    구성이 올바르게 표시되면 다음을 수행합니다.

    • 애플리케이션 로그를 분석합니다.

    • 브라우저의 개발자 도구를 사용하여 클라이언트 앱과 IP 또는 서버 앱 간의 네트워크 트래픽을 검사합니다. 종종 정확한 오류 메시지 또는 문제의 원인에 대한 단서가 있는 메시지가 요청을 수행한 후 IP 또는 서버 앱에 의해 클라이언트로 반환됩니다. 개발자 도구 지침은 다음 문서에서 확인할 수 있습니다.

    • 문제가 발생한 위치에 따라 클라이언트를 인증하거나 서버 웹 API에 액세스하는 데 사용되는 JWT(JSON Web Token)의 콘텐츠를 디코딩합니다. 자세한 내용은 JWT(JSON Web Token)의 콘텐츠 검사를 참조하세요.

    문서 작업 팀은 설명서 피드백 및 문서의 버그에 응답하지만(이 페이지의 피드백 섹션에서 문제 열기) 제품 지원을 제공할 수 없습니다. 앱 문제 해결을 지원하기 위해 몇 가지 퍼블릭 지원 포럼을 사용할 수 있습니다. 다음 방법을 사용하는 것이 좋습니다.

    위의 포럼은 Microsoft에서 소유하거나 관리하지 않습니다.

    중요하지 않고 보안이나 기밀이 아니며 재현 가능한 프레임워크 버그 보고서의 경우 ASP.NET Core 제품 단위에서 문제를 여세요. 문제의 원인을 철저하게 조사했으며 자신의 노력과 퍼블릭 지원 포럼에서 커뮤니티의 도움을 받아도 해결할 수 없는 경우에만 제품 단위에서 문제를 열고 그전에는 열지 마세요. 제품 단위는 단순한 구성 오류 또는 타사 서비스와 관련된 사용 사례로 인해 손상된 개별 앱의 문제를 해결할 수 없습니다. 신고서가 본질적으로 중요하거나 기밀이거나 공격자가 악용할 수 있는 제품의 잠재적인 보안 결함을 설명하는 경우 보안 문제 및 버그 신고(dotnet/aspnetcore GitHub 리포지토리)를 참조하세요.

  • AAD에 대한 권한이 없는 클라이언트

    정보: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2] 권한 부여에 실패했습니다. 다음 요구 사항이 충족되지 않았습니다. DenyAnonymousAuthorizationRequirement: 인증된 사용자가 필요합니다.

    AAD에서 로그인 콜백 오류:

    • 오류: unauthorized_client
    • 설명: AADB2C90058: The provided application is not configured to allow public clients.

    오류를 해결하려면:

    1. Azure Portal에서 앱의 매니페스트에 액세스합니다.
    2. allowPublicClient 특성null 또는 true로 설정합니다.

Cookie 및 사이트 데이터

Cookie 및 사이트 데이터가 앱을 업데이트할 때에도 유지되어 테스트 및 문제 해결에 방해가 될 수 있습니다. 앱 코드를 변경하거나 공급자를 사용하여 사용자 계정을 변경하거나 공급자 앱 구성을 변경하는 경우 다음을 지우세요.

  • 사용자 로그인 cookie
  • 앱 cookie
  • 캐시되고 저장된 사이트 데이터

남겨진 cookie 및 사이트 데이터로 인해 테스트 및 문제 해결이 지장을 받지 않도록 하려면 다음을 수행합니다.

  • 브라우저 구성
    • 브라우저에서 브라우저를 닫을 때마다 모든 cookie 및 사이트 데이터를 삭제하도록 구성할 수 있는지 테스트합니다.
    • 앱, 테스트 사용자 또는 공급자 구성을 변경할 때 수동으로 또는 IDE를 통해 브라우저를 닫습니다.
  • 사용자 지정 명령을 사용하여 Visual Studio에서 시크릿 또는 프라이빗 모드로 브라우저를 엽니다.
    • Visual Studio의 실행 단추를 통해 브라우저 선택 대화 상자를 엽니다.
    • 추가 단추를 선택합니다.
    • 프로그램 필드에서 브라우저의 경로를 제공합니다. 다음 실행 파일 경로는 Windows 10에서 일반적인 설치 위치입니다. 브라우저가 다른 위치에 설치되어 있거나 Windows 10을 사용하지 않는 경우 브라우저 실행 파일의 경로를 제공합니다.
      • Microsoft Edge: C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe
      • Google Chrome: C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
      • Mozilla Firefox: C:\Program Files\Mozilla Firefox\firefox.exe
    • 인수 필드에 브라우저에서 시크릿 또는 프라이빗 모드로 열 때 사용하는 명령줄 옵션을 제공합니다. 일부 브라우저에는 앱의 URL이 필요합니다.
      • Microsoft Edge: -inprivate을 사용하십시오.
      • Google Chrome: --incognito --new-window {URL}를 사용합니다. 여기서 자리 표시자 {URL}은 열려는 URL입니다(예: https://localhost:5001).
      • Mozilla Firefox: -private -url {URL}을 사용합니다. 여기서 자리 표시자 {URL}은 열려는 URL입니다(예: https://localhost:5001).
    • 이름 필드에 이름을 입력합니다. 예: Firefox Auth Testing.
    • 확인 단추를 선택합니다.
    • 앱 테스트를 반복할 때마다 브라우저 프로필을 선택할 필요가 없도록 하려면 기본값으로 설정 단추를 사용하여 프로필을 기본값으로 설정합니다.
    • 앱, 테스트 사용자 또는 공급자 구성을 변경할 때 IDE를 통해 브라우저를 닫습니다.

앱 업그레이드

개발 컴퓨터의 .NET Core SDK 또는 앱 내의 패키지 버전을 업그레이드하거나 앱 내 패키지 버전을 변경한 후 즉시 작동 중인 앱에서 오류가 발생할 수 있습니다. 경우에 따라 중요한 업그레이드를 수행할 때 일관되지 않은 패키지로 인해 응용 프로그램이 중단될 수 있습니다. 이러한 대부분의 문제는 다음 지침에 따라 수정할 수 있습니다.

  1. 명령 셸에서 dotnet nuget locals all --clear를 실행하여 로컬 시스템의 NuGet 패키지 캐시를 지웁니다.
  2. 프로젝트의 binobj 폴더를 삭제합니다.
  3. 프로젝트를 복원하고 다시 빌드합니다.
  4. 앱을 다시 배포하기 전에 서버의 배포 폴더에 있는 모든 파일을 삭제합니다.

참고

앱의 대상 프레임워크와 호환되지 않는 패키지 버전의 사용은 지원되지 않습니다. 패키지에 대한 자세한 내용은 NuGet 갤러리 또는 FuGet 패키지 탐색기를 사용하세요.

서버 앱 실행

호스트된 Blazor WebAssembly솔루션을 테스트하고 문제를 해결할 때 Server 프로젝트에서 앱을 실행하고 있는지 확인합니다. 예를 들어 Visual Studio에서 다음 방법 중 하나를 사용하여 앱을 시작하기 전에 솔루션 탐색기에서 서버 프로젝트가 강조 표시되어 있는지 확인합니다.

  • 실행 단추를 선택합니다.
  • 메뉴에서 디버그>디버깅 시작을 사용합니다.
  • F5키를 누릅니다.

사용자 검사

ASP.NET Core 프레임워크의 테스트 자산에는 Blazor WebAssembly 클라이언트 앱과 문제 해결에 유용할 수 있는 User 구성 요소가 있습니다. User 구성 요소는 앱에서 직접 사용하거나 추가 사용자 지정을 위한 기준으로 사용할 수 있습니다.

dotnet/aspnetcore GitHub 리포지토리User 테스트 구성 요소

참고

.NET 참조 원본의 설명서 링크는 일반적으로 다음 릴리스의 .NET을 위한 현재 개발을 나타내는 리포지토리의 기본 분기를 로드합니다. 특정 릴리스를 위한 태그를 선택하려면 Switch branches or tags(분기 또는 태그 전환) 드롭다운 목록을 사용합니다. 자세한 내용은 ASP.NET Core 소스 코드(dotnet/AspNetCore.Docs #26205)의 버전 태그를 선택하는 방법을 참조하세요.

JWT(JSON Web Token)의 콘텐츠 검사

JWT(JSON Web Token)를 디코딩하려면 Microsoft의 jwt.ms 도구를 사용합니다. UI의 값은 브라우저에 남겨지지 않습니다.

인코딩된 JWT 예제(표시를 위해 축약됨):

eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ilg1ZVhrNHh5b2pORnVtMWtsMll0djhkbE5QNC1j ... bQdHBHGcQQRbW7Wmo6SWYG4V_bU55Ug_PW4pLPr20tTS8Ct7_uwy9DWrzCMzpD-EiwT5IjXwlGX3IXVjHIlX50IVIydBoPQtadvT7saKo1G5Jmutgq41o-dmz6-yBMKV2_nXA25Q

Azure AAD B2C에 대해 인증하는 앱용 도구에 의해 디코딩된 JWT 예제:

{
  "typ": "JWT",
  "alg": "RS256",
  "kid": "X5eXk4xyojNFum1kl2Ytv8dlNP4-c57dO6QGTVBwaNk"
}.{
  "exp": 1610059429,
  "nbf": 1610055829,
  "ver": "1.0",
  "iss": "https://mysiteb2c.b2clogin.com/5cc15ea8-a296-4aa3-97e4-226dcc9ad298/v2.0/",
  "sub": "5ee963fb-24d6-4d72-a1b6-889c6e2c7438",
  "aud": "70bde375-fce3-4b82-984a-b247d823a03f",
  "nonce": "b2641f54-8dc4-42ca-97ea-7f12ff4af871",
  "iat": 1610055829,
  "auth_time": 1610055822,
  "idp": "idp.com",
  "tfp": "B2C_1_signupsignin"
}.[Signature]

추가 자료

AAD B2C에 앱을 등록하고 솔루션 만들기

테넌트 만들기

자습서: Azure Active Directory B2C 테넌트 만들기의 지침에 따라 AAD B2C 테넌트를 만듭니다. 사용할 테넌트를 만들거나 식별한 직후 이 문서로 돌아옵니다.

AAD B2C 인스턴스를 기록해 둡니다(예: 후행 슬래시를 포함하는 https://contoso.b2clogin.com/). 이 인스턴스는 Azure B2C 앱 등록의 스키마 및 호스트로, Azure Portal의 앱 등록 페이지에서 엔드포인트 창을 열어 찾을 수 있습니다.

서버 API 앱 등록

서버 API 앱을 위한 AAD B2C 앱을 등록합니다.

  1. Azure Portal에서 Azure Active Directory로 이동합니다. 사이드바에서 앱 등록을 선택합니다. 새 등록 단추를 선택합니다.
  2. 앱의 이름을 지정합니다(예: Blazor Server AAD B2C).
  3. 지원되는 계정 유형으로 다중 테넌트 옵션 모든 ID 공급자 또는 조직 디렉터리의 계정(사용자 흐름을 사용하여 사용자를 인증하는 경우)
  4. 이 시나리오에서는 ‘서버 API 앱’에 리디렉션 URI가 필요하지 않으므로 드롭다운이 으로 설정된 상태로 두고 리디렉션 URI를 입력하지 않습니다.
  5. 확인되지 않은 게시자 도메인을 사용하는 경우 권한>openid 및 offline_access 권한에 대한 관리자 동의 허용을 선택 취소했는지 확인합니다. 게시자 도메인이 확인된 경우에는 이 확인란이 표시되지 않습니다.
  6. 등록을 선택합니다.

다음과 같은 정보를 기록해 둡니다.

  • 서버 API 앱 애플리케이션(클라이언트) ID(예: 41451fa7-82d9-4673-8fa5-69eff5a761fd)
  • AAD 주/게시자/테넌트 도메인(예: contoso.onmicrosoft.com): 도메인은 Azure Portal에서 등록된 앱의 브랜딩 블레이드에 게시자 도메인으로 표시되어 있습니다.

API 표시에서:

  1. 범위 추가를 선택합니다.
  2. 저장 및 계속을 선택합니다.
  3. 범위 이름을 지정합니다(예: API.Access).
  4. 관리자 동의 표시 이름을 지정합니다(예: Access API).
  5. 관리자 동의 설명을 지정합니다(예: Allows the app to access server app API endpoints.).
  6. 상태사용으로 설정되었는지 확인합니다.
  7. 범위 추가를 선택합니다.

다음과 같은 정보를 기록해 둡니다.

  • 앱 ID URI(예: api://41451fa7-82d9-4673-8fa5-69eff5a761fd, https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd 또는 사용자가 지정한 사용자 지정 값)
  • 범위 이름(예: API.Access)

클라이언트 앱 등록

클라이언트 앱을 위한 AAD B2C 앱을 등록합니다.

  1. Azure Portal에서 Azure Active Directory로 이동합니다. 사이드바에서 앱 등록을 선택합니다. 새 등록 단추를 선택합니다.
  2. 앱의 이름을 지정합니다(예: Blazor 클라이언트 AAD B2C).
  3. 지원되는 계정 유형으로 다중 테넌트 옵션 모든 ID 공급자 또는 조직 디렉터리의 계정(사용자 흐름을 사용하여 사용자를 인증하는 경우)
  4. 리디렉션 URI 드롭다운은 SPA(단일 페이지 애플리케이션) 으로 설정하고 리디렉션 URI를 https://localhost/authentication/login-callback으로 지정합니다. Azure 기본 호스트에 대한 프로덕션 리디렉션 URI(예: azurewebsites.net) 또는 사용자 지정 도메인 호스트(예: contoso.com)를 알고 있는 경우 localhost 리디렉션 URI를 제공하는 동시에 프로덕션 리디렉션 URI를 추가할 수도 있습니다. 추가하는 프로덕션 리디렉션 URI에 비 :443 포트에 대한 포트 번호를 포함해야 합니다.
  5. 확인되지 않은 게시자 도메인을 사용하는 경우 권한>openid 및 offline_access 권한에 대한 관리자 동의 허용을 선택 취소했는지 확인합니다. 게시자 도메인이 확인된 경우에는 이 확인란이 표시되지 않습니다.
  6. 등록을 선택합니다.

참고

localhost AAD B2C 리디렉션 URI에 대한 포트 번호를 제공할 필요는 없습니다. 자세한 내용은 Redirect URI(회신 URL) 제한 사항: Localhost 예외(Azure 설명서)를 참조하세요.

애플리케이션(클라이언트) ID를 기록해 둡니다(예: 4369008b-21fa-427c-abaa-9b53bf58e538).

인증>플랫폼 구성>SPA(단일 페이지 애플리케이션)에서 다음을 수행합니다.

  1. https://localhost/authentication/login-callback리디렉션 URI가 있는지 확인합니다.
  2. 암시적 허용 섹션에서 액세스 토큰ID 토큰의 확인란을 선택 해제 상태로 유지합니다.
  3. 이 환경에서는 앱의 나머지 기본값을 그대로 사용해도 좋습니다.
  4. 저장 단추를 선택합니다.

API 사용 권한에서:

  1. 사용 권한 추가를 선택하고 내 API를 선택합니다.
  2. 이름 열에서 ‘서버 API 앱’을 선택합니다(예: Blazor Server AAD B2C).
  3. API 목록을 엽니다.
  4. API에 대한 액세스를 사용하도록 설정합니다(예: API.Access).
  5. 권한 추가를 선택합니다.
  6. {테넌트 이름}에 대한 관리자 동의 허용 단추를 선택합니다. 를 선택하여 확인합니다.

중요

앱 사용에 대한 동의가 사용자에게 위임되므로 API 권한 구성의 마지막 단계에서 테넌트에 관리자 동의를 부여할 권한이 없는 경우 다음 추가 단계를 수행해야 합니다.

  • 앱은 신뢰할 수 있는 게시자 도메인을 사용해야 합니다.
  • Azure Portal의 Server 앱 구성에서 API 공개를 선택합니다. 권한 있는 클라이언트 애플리케이션에서 클라이언트 애플리케이션 추가 단추를 선택합니다. Client 앱의 애플리케이션(클라이언트) ID를 추가합니다(예: 4369008b-21fa-427c-abaa-9b53bf58e538).

Home>Azure AD B2C>사용자 흐름에서 다음을 수행합니다.

가입 및 로그인 사용자 흐름 만들기

최소한 애플리케이션 클레임>표시 이름 사용자 특성을 선택하여 LoginDisplay 구성 요소(Shared/LoginDisplay.razor)의 context.User.Identity.Name을 채웁니다.

앱에 대해 만들어진 가입 및 로그인 사용자 흐름 이름을 기록해 둡니다(예: B2C_1_signupsignin).

앱 만들기

다음 명령에서 자리 표시자를 앞에서 기록해 둔 정보로 바꾸고 명령 셸에서 명령을 실행합니다.

dotnet new blazorwasm -au IndividualB2C --aad-b2c-instance "{AAD B2C INSTANCE}" --api-client-id "{SERVER API APP CLIENT ID}" --app-id-uri "{SERVER API APP ID URI}" --client-id "{CLIENT APP CLIENT ID}" --default-scope "{DEFAULT SCOPE}" --domain "{TENANT DOMAIN}" -ho -o {APP NAME} -ssp "{SIGN UP OR SIGN IN POLICY}"

경고

OIDC 앱 식별자의 형성을 중단하는 대시(-)를 앱 이름 {APP NAME}에 사용하지 마세요. Blazor WebAssembly 프로젝트 템플릿의 논리는 솔루션 구성에서 OIDC 앱 식별자에 대해 프로젝트 이름을 사용합니다. 파스칼식 대/소문자(BlazorSample) 또는 밑줄(Blazor_Sample)은 사용 가능한 대안입니다. 자세한 내용은 호스트된 Blazor WebAssembly 프로젝트 이름의 대시가 OIDC 보안 중단(dotnet/aspnetcore #35337)을 참조하세요.

자리표시자 Azure Portal 이름 예제
{AAD B2C INSTANCE} 인스턴스 https://contoso.b2clogin.com/
{APP NAME} BlazorSample
{CLIENT APP CLIENT ID} Client 앱의 애플리케이션(클라이언트) ID 4369008b-21fa-427c-abaa-9b53bf58e538
{DEFAULT SCOPE} 범위 이름 API.Access
{SERVER API APP CLIENT ID} 서버 API 앱의 애플리케이션(클라이언트) ID 41451fa7-82d9-4673-8fa5-69eff5a761fd
{SERVER API APP ID URI} 애플리케이션 ID URI† 41451fa7-82d9-4673-8fa5-69eff5a761fd
{SIGN UP OR SIGN IN POLICY} 가입/로그인 사용자 흐름 B2C_1_signupsignin1
{TENANT DOMAIN} 주/게시자/테넌트 도메인 contoso.onmicrosoft.com

†Blazor WebAssembly 템플릿은 dotnet new 명령에 전달된 앱 ID URI 인수에 api://의 구성표를 자동으로 추가합니다. {SERVER API APP ID URI} 자리 표시자의 앱 ID URI를 제공할 때 구성표가 api://인 경우 앞의 테이블에 나온 것처럼 인수에서 구성표(api://)를 제거하세요. 앱 ID URI가 사용자 지정 값이거나 다른 구성표(예를 들어 https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd와 유사한 확인되지 않은 게시자 도메인에 대해 https://)를 갖는 경우 기본 범위 URI를 수동으로 업데이트하고 템플릿이 Client 앱을 만든 후 api:// 구성표를 제거해야 합니다. 자세한 내용은 액세스 토큰 범위 섹션의 참고를 참조하세요. 이러한 시나리오를 해결하기 위해 ASP.NET Core의 이후 릴리스에서 Blazor WebAssembly 템플릿이 변경될 수 있습니다. 자세한 내용은 Double scheme for App ID URI with Blazor WASM template (hosted, single org) (dotnet/aspnetcore #27417)을 참조하세요.

-o|--output 옵션으로 지정된 출력 위치는 프로젝트 폴더가 없는 경우 폴더를 하나 만들고 앱 이름의 일부가 됩니다. OIDC 앱 식별자의 형성을 중단하는 대시(-)를 앱 이름에 사용하지 마세요(앞에 나온 경고 참조).

참고

Blazor WebAssembly 프로젝트 템플릿에서 호스티된 Blazor WebAssembly 솔루션에 설정한 범위에서는 앱 ID URI 호스트가 반복될 수 있습니다. Client 앱의 Program.cs에서 DefaultAccessTokenScopes 컬렉션에 대해 구성된 범위가 올바른지 확인합니다.

Server 앱 구성

이 섹션은 솔루션의 Server 앱에 적용됩니다.

인증 패키지

Microsoft Identity 플랫폼을 통한 ASP.NET Core Web API에 대한 호출의 권한 부여 및 인증 지원은 Microsoft.Identity.Web 패키지에서 제공합니다.

참고

.NET 앱에 패키지를 추가하는 지침은 패키지 사용 워크플로(NuGet 설명서)에서 패키지 설치 및 관리 아래의 문서를 참조하세요. NuGet.org에서 올바른 패키지 버전을 확인합니다.

Blazor WebAssembly 템플릿에서 만든 호스트된 Blazor 솔루션의 Server 앱에는 기본적으로 Microsoft.Identity.Web.UI 패키지가 포함됩니다. 패키지는 웹앱에서 사용자 인증을 위한 UI를 추가하며 Blazor 프레임워크에서 사용되지 않습니다. Server 앱을 사용하여 사용자를 직접 인증하지 않는 경우 Server 앱의 프로젝트 파일에서 패키지 참조를 제거하는 것이 안전합니다.

인증 서비스 지원

AddAuthentication 메서드는 앱 내에서 인증 서비스를 설정하고 JWT 전달자 처리기를 기본 인증 메서드로 구성합니다. AddMicrosoftIdentityWebApi 메서드는 Microsoft Identity 플랫폼 v2.0을 사용하여 웹 API를 보호하도록 서비스를 구성합니다. 이 메서드에는 인증 옵션을 초기화하는 데 필요한 설정을 포함하는 앱 구성의 AzureAdB2C 섹션이 필요합니다.

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAdB2C"));

UseAuthenticationUseAuthorization은 다음을 수행합니다.

  • 앱이 수신 요청에 대해 토큰의 구문 분석 및 유효성 검사를 시도하도록 합니다.
  • 올바른 자격 증명 없이 보호된 리소스에 액세스하려는 요청은 모두 실패하도록 합니다.
app.UseAuthentication();
app.UseAuthorization();

User.Identity.Name

기본적으로 User.Identity.Name은 채워지지 않습니다.

name 클레임 유형에서 값을 받도록 앱을 구성하려면 다음을 수행합니다.

앱 설정

appsettings.json 파일은 액세스 토큰의 유효성을 검사하는 데 사용되는 JWT 전달자 처리기를 구성하기 위한 옵션을 포함합니다.

{
  "AzureAdB2C": {
    "Instance": "https://{TENANT}.b2clogin.com/",
    "ClientId": "{SERVER API APP CLIENT ID}",
    "Domain": "{TENANT DOMAIN}",
    "SignUpSignInPolicyId": "{SIGN UP OR SIGN IN POLICY}"
  }
}

예:

{
  "AzureAdB2C": {
    "Instance": "https://contoso.b2clogin.com/",
    "ClientId": "41451fa7-82d9-4673-8fa5-69eff5a761fd",
    "Domain": "contoso.onmicrosoft.com",
    "SignUpSignInPolicyId": "B2C_1_signupsignin1",
  }
}

WeatherForecast 컨트롤러

WeatherForecast 컨트롤러(Controllers/WeatherForecastController.cs)는 컨트롤러에 적용된 [Authorize] 특성으로 보호된 API를 노출합니다. 다음과 같은 사항을 이해하는 것이 중요합니다.

  • 이 API 컨트롤러의 [Authorize] 특성은 무단 액세스로부터 이 API를 보호하는 유일한 항목입니다.
  • Blazor WebAssembly 앱에서 사용되는 [Authorize] 특성은 앱이 올바르게 작동하려면 사용자에게 권한이 부여되어야 한다는 힌트로만 앱에 제공됩니다.
[Authorize]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    [HttpGet]
    public IEnumerable<WeatherForecast> Get()
    {
        ...
    }
}

Client 앱 구성

이 섹션은 솔루션의 Client 앱에 적용됩니다.

인증 패키지

앱이 개별 B2C 계정을 사용하도록 만들어진 경우(IndividualB2C) 해당 앱은 자동으로 Microsoft 인증 라이브러리(Microsoft.Authentication.WebAssembly.Msal)에 대한 패키지 참조를 받습니다. 패키지는 앱이 사용자를 인증하고 보호된 API를 호출하는 데 사용할 토큰을 가져올 수 있도록 지원하는 기본 형식 세트를 제공합니다.

앱에 인증을 추가하는 경우에는 Microsoft.Authentication.WebAssembly.Msal 패키지를 앱에 수동으로 추가합니다.

참고

.NET 앱에 패키지를 추가하는 지침은 패키지 사용 워크플로(NuGet 설명서)에서 패키지 설치 및 관리 아래의 문서를 참조하세요. NuGet.org에서 올바른 패키지 버전을 확인합니다.

Microsoft.Authentication.WebAssembly.Msal 패키지는 타동적으로 Microsoft.AspNetCore.Components.WebAssembly.Authentication 패키지를 앱에 추가합니다.

인증 서비스 지원

서버 프로젝트로 요청을 전송할 때 액세스 토큰을 포함하는 HttpClient 인스턴스에 대한 지원이 추가됩니다.

Program.cs:

builder.Services.AddHttpClient("{APP ASSEMBLY}.ServerAPI", client => 
    client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
    .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();

builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>()
    .CreateClient("{APP ASSEMBLY}.ServerAPI"));

자리 표시자 {APP ASSEMBLY}는 앱의 어셈블리 이름입니다(예: BlazorSample.Client).

사용자 인증에 대한 지원은 Microsoft.Authentication.WebAssembly.Msal 패키지에서 제공하는 AddMsalAuthentication 확장 메서드를 통해 서비스 컨테이너에 등록됩니다. 이 메서드는 앱이 IP(Identity 공급자)와 상호 작용하는 데 필요한 서비스를 설정합니다.

Program.cs:

builder.Services.AddMsalAuthentication(options =>
{
    builder.Configuration.Bind("AzureAdB2C", options.ProviderOptions.Authentication);
    options.ProviderOptions.DefaultAccessTokenScopes.Add("{SCOPE URI}");
});

AddMsalAuthentication 메서드는 콜백을 받아서 앱을 인증하는 데 필요한 매개 변수를 구성합니다. 앱을 구성하는 데 필요한 값은 앱을 등록할 때 Azure Portal AAD 구성에서 얻을 수 있습니다.

구성은 wwwroot/appsettings.json 파일에서 제공합니다.

{
  "AzureAdB2C": {
    "Authority": "{AAD B2C INSTANCE}{TENANT DOMAIN}/{SIGN UP OR SIGN IN POLICY}",
    "ClientId": "{CLIENT APP CLIENT ID}",
    "ValidateAuthority": false
  }
}

예:

{
  "AzureAdB2C": {
    "Authority": "https://contoso.b2clogin.com/contoso.onmicrosoft.com/B2C_1_signupsignin1",
    "ClientId": "4369008b-21fa-427c-abaa-9b53bf58e538",
    "ValidateAuthority": false
  }
}

액세스 토큰 범위

기본 액세스 토큰 범위는 다음과 같은 액세스 토큰 범위 목록을 나타냅니다.

  • 기본적으로 로그인 요청에 포함되어 있음.
  • 인증 직후에 액세스 토큰을 프로비저닝하는 데 사용됨.

모든 범위는 Azure Active Directory 규칙에 따라 동일한 앱에 속해 있어야 합니다. 필요에 따라 추가 API 앱에 대한 추가 범위가 추가될 수 있습니다.

builder.Services.AddMsalAuthentication(options =>
{
    ...
    options.ProviderOptions.DefaultAccessTokenScopes.Add("{SCOPE URI}");
});

참고

Blazor WebAssembly 템플릿은 dotnet new 명령에 전달된 앱 ID URI 인수에 api://의 구성표를 자동으로 추가합니다. Blazor 프로젝트 템플릿에서 앱을 생성할 때 기본 액세스 토큰 범위의 값이 Azure Portal에 제공한 올바른 사용자 지정 앱 ID URI 값 또는 다음 형식 중 하나인 값을 사용하는지 확인합니다.

  • 디렉터리의 게시자 도메인을 신뢰할 수 있는 경우 기본 액세스 토큰 범위는 일반적으로 다음 예제와 비슷한 값입니다. 여기서 API.Access는 기본 범위 이름입니다.

    options.ProviderOptions.DefaultAccessTokenScopes.Add(
        "api://41451fa7-82d9-4673-8fa5-69eff5a761fd/API.Access");
    

    이중 구성표(api://api://...)의 값을 검사합니다. 이중 구성표가 있는 경우 값에서 첫 번째 api:// 구성표를 제거합니다.

  • 디렉터리의 게시자 도메인을 신뢰할 수 없는 경우 기본 액세스 토큰 범위는 일반적으로 다음 예제와 비슷한 값입니다. 여기서 API.Access는 기본 범위 이름입니다.

    options.ProviderOptions.DefaultAccessTokenScopes.Add(
        "https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd/API.Access");
    

    추가 api:// 구성표(api://https://contoso.onmicrosoft.com/...)의 값을 검사합니다. 추가 api:// 구성표가 있는 경우 값에서 api:// 구성표를 제거합니다.

이러한 시나리오를 해결하기 위해 ASP.NET Core의 이후 릴리스에서 Blazor WebAssembly 템플릿이 변경될 수 있습니다. 자세한 내용은 Double scheme for App ID URI with Blazor WASM template (hosted, single org) (dotnet/aspnetcore #27417)을 참조하세요.

AdditionalScopesToConsent를 사용하여 추가 범위를 지정합니다.

options.ProviderOptions.AdditionalScopesToConsent.Add("{ADDITIONAL SCOPE URI}");

자세한 내용은 ‘추가 시나리오’ 문서의 다음 섹션을 참조하세요.

로그인 모드

프레임워크는 기본적으로 팝업 로그인 모드로 설정되며 팝업을 열 수 없는 경우 리디렉션 로그인 모드로 대체됩니다. MsalProviderOptionsLoginMode 속성을 redirect로 설정하여 리디렉션 로그인 모드를 사용하도록 MSAL을 구성합니다.

builder.Services.AddMsalAuthentication(options =>
{
    ...
    options.ProviderOptions.LoginMode = "redirect";
});

기본 설정은 popup이며 문자열 값은 대/소문자를 구분하지 않습니다.

Imports 파일

Microsoft.AspNetCore.Components.Authorization 네임스페이스는 _Imports.razor 파일을 통해 앱 전체에서 사용할 수 있게 됩니다.

@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Microsoft.JSInterop
@using {APPLICATION ASSEMBLY}.Client
@using {APPLICATION ASSEMBLY}.Client.Shared

인덱스 페이지

인덱스 페이지(wwwroot/index.html)는 JavaScript로 AuthenticationService를 정의하는 스크립트를 포함합니다. AuthenticationService는 OIDC 프로토콜의 하위 수준 세부 정보를 처리합니다. 앱은 내부적으로 스크립트에 정의된 메서드를 호출하여 인증 작업을 수행합니다.

<script src="_content/Microsoft.Authentication.WebAssembly.Msal/AuthenticationService.js"></script>

App 구성 요소

App 구성 요소(App.razor)는 Blazor Server 앱에 있는 App 구성 요소와 비슷합니다.

  • CascadingAuthenticationState 구성 요소는 앱의 나머지 부분에 AuthenticationState를 노출하는 것을 관리합니다.
  • AuthorizeRouteView 구성 요소는 현재 사용자가 지정된 페이지에 액세스할 수 있는 권한이 부여받았는지 확인하고 그러지 않은 경우 RedirectToLogin 구성 요소를 렌더링합니다.
  • RedirectToLogin 구성 요소는 권한 없는 사용자를 로그인 페이지로 리디렉션하는 기능을 관리합니다.

ASP.NET Core 릴리스 간 프레임워크 변경으로 인해 App 구성 요소의 Razor 변경 내용(App.razor)은 이 섹션에 표시되지 않습니다. 지정된 릴리스의 구성 요소의 변경 내용을 검사하려면 다음 방법 중 하나를 사용합니다.

  • 사용하려는 ASP.NET Core 버전의 기본 Blazor WebAssembly 프로젝트 템플릿에서 인증을 위해 프로비전된 앱을 만듭니다. 생성된 앱에서 App 구성 요소(App.razor)를 검사합니다.

  • 참조 소스에서 App 구성 요소(App.razor)를 검사합니다.

    참고

    .NET 참조 원본의 설명서 링크는 일반적으로 다음 릴리스의 .NET을 위한 현재 개발을 나타내는 리포지토리의 기본 분기를 로드합니다. 특정 릴리스를 위한 태그를 선택하려면 Switch branches or tags(분기 또는 태그 전환) 드롭다운 목록을 사용합니다. 자세한 내용은 ASP.NET Core 소스 코드(dotnet/AspNetCore.Docs #26205)의 버전 태그를 선택하는 방법을 참조하세요.

RedirectToLogin 구성 요소

RedirectToLogin 구성 요소(Shared/RedirectToLogin.razor)는 다음을 수행합니다.

  • 로그인 페이지로의 권한 없는 사용자 리디렉션을 관리합니다.
  • 사용자가 인증에 성공하면 해당 페이지로 되돌아올 수 있도록 사용자가 액세스하려고 하는 현재 URL을 유지합니다.
@inject NavigationManager Navigation
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@code {
    protected override void OnInitialized()
    {
        Navigation.NavigateTo(
            $"authentication/login?returnUrl={Uri.EscapeDataString(Navigation.Uri)}");
    }
}

LoginDisplay 구성 요소

LoginDisplay 구성 요소(Shared/LoginDisplay.razor)는 MainLayout 구성 요소(Shared/MainLayout.razor)에서 렌더링되고 다음 동작을 관리합니다.

  • 인증된 사용자의 경우:
    • 현재 사용자 이름을 표시합니다.
    • 앱에서 로그아웃하는 단추를 제공합니다.
  • 익명 사용자의 경우, 로그인 옵션을 제공합니다.
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject NavigationManager Navigation
@inject SignOutSessionStateManager SignOutManager

<AuthorizeView>
    <Authorized>
        Hello, @context.User.Identity.Name!
        <button class="nav-link btn btn-link" @onclick="BeginLogout">
            Log out
        </button>
    </Authorized>
    <NotAuthorized>
        <a href="authentication/login">Log in</a>
    </NotAuthorized>
</AuthorizeView>

@code {
    private async Task BeginLogout(MouseEventArgs args)
    {
        await SignOutManager.SetSignOutState();
        Navigation.NavigateTo("authentication/logout");
    }
}

Authentication 구성 요소

Authentication 구성 요소에 의해 생성된 페이지(Pages/Authentication.razor)는 다른 인증 단계를 처리하는 데 필요한 경로를 정의합니다.

RemoteAuthenticatorView 구성 요소는 다음과 같습니다.

@page "/authentication/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication

<RemoteAuthenticatorView Action="@Action" />

@code {
    [Parameter]
    public string Action { get; set; }
}

FetchData 구성 요소

FetchData 구성 요소는 다음을 수행하는 방법을 보여 줍니다.

  • 액세스 토큰을 프로비저닝합니다.
  • 액세스 토큰을 사용하여 ‘서버’ 앱에서 보호된 리소스 API를 호출합니다.

@attribute [Authorize] 지시문은 사용자가 이 구성 요소에 액세스하기 위해 권한을 부여받아야 한다는 것을 Blazor WebAssembly 권한 부여 시스템에 나타냅니다. Client 앱에 특성이 있으면 서버에 있는 API가 적절한 자격 증명 없이 호출되는 것을 방지하지 않습니다. 또한 Server 앱은 적절한 엔드포인트에서 [Authorize]를 사용하여 올바로 보호해야 합니다.

IAccessTokenProvider.RequestAccessToken은 API를 호출하는 요청에 추가할 수 있는 액세스 토큰을 요청하는 작업을 처리합니다. 토큰이 캐시되었거나 서비스에서 사용자 개입 없이 새 액세스 토큰을 프로비저닝할 수 있으면 토큰 요청이 성공합니다. 그러지 않으면 토큰 요청이 실패하고 AccessTokenNotAvailableExceptiontry-catch 문에 catch됩니다.

요청에 포함할 실제 토큰을 가져오려면 앱에서 tokenResult.TryGetToken(out var token)을 호출하여 요청이 성공했는지 확인해야 합니다.

요청이 성공하면 토큰 변수가 액세스 토큰으로 채워집니다. 토큰의 AccessToken.Value 속성은 Authorization 요청 헤더에 포함할 리터럴 문자열을 노출합니다.

사용자 개입 없이 토큰을 프로비저닝할 수 없어 요청이 실패한 경우 토큰 결과에 리디렉션 URL이 포함됩니다. 이 URL로 이동하면 사용자가 로그인 페이지로 이동하고 인증 성공 후 현재 페이지로 돌아옵니다.

@page "/fetchdata"
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using {APP NAMESPACE}.Shared
@attribute [Authorize]
@inject HttpClient Http

...

@code {
    private WeatherForecast[] forecasts;

    protected override async Task OnInitializedAsync()
    {
        try
        {
            forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
    }
}

앱 실행

서버 프로젝트에서 앱을 실행합니다. Visual Studio를 사용하는 경우 다음 중 하나를 수행합니다.

  • 도구 모음의 시작 프로젝트 드롭다운 목록을 ‘서버 API 앱’으로 설정하고 실행 단추를 선택합니다.
  • 솔루션 탐색기에서 서버 프로젝트를 선택하고 도구 모음에서 실행 단추를 선택하거나 디버그 메뉴에서 앱을 시작합니다.

UserManagerSignInManager

서버 앱에 다음이 필요한 경우 사용자 ID 클레임 유형을 설정합니다.

ASP.NET Core 6.0 이상의 Program.cs에서 다음을 수행합니다.

using System.Security.Claims;

...

builder.Services.Configure<IdentityOptions>(options => 
    options.ClaimsIdentity.UserIdClaimType = ClaimTypes.NameIdentifier);

ASP.NET Core 6.0 이전 버전의 Startup.ConfigureServices에서:

using System.Security.Claims;

...

services.Configure<IdentityOptions>(options => 
    options.ClaimsIdentity.UserIdClaimType = ClaimTypes.NameIdentifier);

다음 WeatherForecastControllerGet 메서드가 호출될 때 UserName을 로깅합니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using BlazorSample.Server.Models;
using BlazorSample.Shared;

namespace BlazorSample.Server.Controllers
{
    [Authorize]
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        private readonly UserManager<ApplicationUser> userManager;

        private static readonly string[] Summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", 
            "Balmy", "Hot", "Sweltering", "Scorching"
        };

        private readonly ILogger<WeatherForecastController> logger;

        public WeatherForecastController(ILogger<WeatherForecastController> logger, 
            UserManager<ApplicationUser> userManager)
        {
            this.logger = logger;
            this.userManager = userManager;
        }

        [HttpGet]
        public async Task<IEnumerable<WeatherForecast>> Get()
        {
            var rng = new Random();

            var user = await userManager.GetUserAsync(User);

            if (user != null)
            {
                logger.LogInformation($"User.Identity.Name: {user.UserName}");
            }

            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = rng.Next(-20, 55),
                Summary = Summaries[rng.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }
}

이전 예제에서는 다음을 수행합니다.

  • Server 프로젝트의 네임스페이스는 BlazorSample.Server입니다.
  • Shared 프로젝트의 네임스페이스는 BlazorSample.Shared입니다.

사용자 지정 사용자 흐름

Microsoft 인증 라이브러리(Microsoft.Authentication.WebAssembly.Msal, NuGet 패키지)는 기본적으로 AAD B2C 사용자 흐름을 지원하지 않습니다. 개발자 코드에서 사용자 지정 사용자 흐름을 만듭니다.

사용자 지정 사용자 흐름의 챌린지를 작성하는 방법에 대한 자세한 내용은 Azure Active Directory B2C의 사용자 흐름을 참조하세요.

문제 해결

일반 오류

  • 앱 또는 IP(Identity 공급자)의 잘못된 구성

    가장 일반적인 오류는 잘못된 구성으로 인해 발생합니다. 다음은 몇 가지 예제입니다.

    • 시나리오의 요구 사항에 따라, 누락되거나 잘못된 권한, 인스턴스, 테넌트 ID, 테넌트 도메인, 클라이언트 ID 또는 리디렉션 URI 때문에 앱에서 클라이언트를 인증하지 못합니다.
    • 액세스 토큰 범위가 잘못되어 클라이언트가 서버 웹 API 엔드포인트에 액세스하지 못합니다.
    • 서버 API 권한이 잘못되거나 누락되어 클라이언트가 서버 웹 API 엔드포인트에 액세스할 수 없습니다.
    • Identity 공급자 앱 등록의 리디렉션 URI에 구성된 것과 다른 포트에서 앱을 실행합니다.

    이 문서 지침의 구성 섹션에서는 올바른 구성의 예를 보여 줍니다. 앱 및 IP 구성을 찾는 문서의 각 섹션을 주의 깊게 확인하세요.

    구성이 올바르게 표시되면 다음을 수행합니다.

    • 애플리케이션 로그를 분석합니다.

    • 브라우저의 개발자 도구를 사용하여 클라이언트 앱과 IP 또는 서버 앱 간의 네트워크 트래픽을 검사합니다. 종종 정확한 오류 메시지 또는 문제의 원인에 대한 단서가 있는 메시지가 요청을 수행한 후 IP 또는 서버 앱에 의해 클라이언트로 반환됩니다. 개발자 도구 지침은 다음 문서에서 확인할 수 있습니다.

    • 문제가 발생한 위치에 따라 클라이언트를 인증하거나 서버 웹 API에 액세스하는 데 사용되는 JWT(JSON Web Token)의 콘텐츠를 디코딩합니다. 자세한 내용은 JWT(JSON Web Token)의 콘텐츠 검사를 참조하세요.

    문서 작업 팀은 설명서 피드백 및 문서의 버그에 응답하지만(이 페이지의 피드백 섹션에서 문제 열기) 제품 지원을 제공할 수 없습니다. 앱 문제 해결을 지원하기 위해 몇 가지 퍼블릭 지원 포럼을 사용할 수 있습니다. 다음 방법을 사용하는 것이 좋습니다.

    위의 포럼은 Microsoft에서 소유하거나 관리하지 않습니다.

    중요하지 않고 보안이나 기밀이 아니며 재현 가능한 프레임워크 버그 보고서의 경우 ASP.NET Core 제품 단위에서 문제를 여세요. 문제의 원인을 철저하게 조사했으며 자신의 노력과 퍼블릭 지원 포럼에서 커뮤니티의 도움을 받아도 해결할 수 없는 경우에만 제품 단위에서 문제를 열고 그전에는 열지 마세요. 제품 단위는 단순한 구성 오류 또는 타사 서비스와 관련된 사용 사례로 인해 손상된 개별 앱의 문제를 해결할 수 없습니다. 신고서가 본질적으로 중요하거나 기밀이거나 공격자가 악용할 수 있는 제품의 잠재적인 보안 결함을 설명하는 경우 보안 문제 및 버그 신고(dotnet/aspnetcore GitHub 리포지토리)를 참조하세요.

  • AAD에 대한 권한이 없는 클라이언트

    정보: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2] 권한 부여에 실패했습니다. 다음 요구 사항이 충족되지 않았습니다. DenyAnonymousAuthorizationRequirement: 인증된 사용자가 필요합니다.

    AAD에서 로그인 콜백 오류:

    • 오류: unauthorized_client
    • 설명: AADB2C90058: The provided application is not configured to allow public clients.

    오류를 해결하려면:

    1. Azure Portal에서 앱의 매니페스트에 액세스합니다.
    2. allowPublicClient 특성null 또는 true로 설정합니다.

Cookie 및 사이트 데이터

Cookie 및 사이트 데이터가 앱을 업데이트할 때에도 유지되어 테스트 및 문제 해결에 방해가 될 수 있습니다. 앱 코드를 변경하거나 공급자를 사용하여 사용자 계정을 변경하거나 공급자 앱 구성을 변경하는 경우 다음을 지우세요.

  • 사용자 로그인 cookie
  • 앱 cookie
  • 캐시되고 저장된 사이트 데이터

남겨진 cookie 및 사이트 데이터로 인해 테스트 및 문제 해결이 지장을 받지 않도록 하려면 다음을 수행합니다.

  • 브라우저 구성
    • 브라우저에서 브라우저를 닫을 때마다 모든 cookie 및 사이트 데이터를 삭제하도록 구성할 수 있는지 테스트합니다.
    • 앱, 테스트 사용자 또는 공급자 구성을 변경할 때 수동으로 또는 IDE를 통해 브라우저를 닫습니다.
  • 사용자 지정 명령을 사용하여 Visual Studio에서 시크릿 또는 프라이빗 모드로 브라우저를 엽니다.
    • Visual Studio의 실행 단추를 통해 브라우저 선택 대화 상자를 엽니다.
    • 추가 단추를 선택합니다.
    • 프로그램 필드에서 브라우저의 경로를 제공합니다. 다음 실행 파일 경로는 Windows 10에서 일반적인 설치 위치입니다. 브라우저가 다른 위치에 설치되어 있거나 Windows 10을 사용하지 않는 경우 브라우저 실행 파일의 경로를 제공합니다.
      • Microsoft Edge: C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe
      • Google Chrome: C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
      • Mozilla Firefox: C:\Program Files\Mozilla Firefox\firefox.exe
    • 인수 필드에 브라우저에서 시크릿 또는 프라이빗 모드로 열 때 사용하는 명령줄 옵션을 제공합니다. 일부 브라우저에는 앱의 URL이 필요합니다.
      • Microsoft Edge: -inprivate을 사용하십시오.
      • Google Chrome: --incognito --new-window {URL}를 사용합니다. 여기서 자리 표시자 {URL}은 열려는 URL입니다(예: https://localhost:5001).
      • Mozilla Firefox: -private -url {URL}을 사용합니다. 여기서 자리 표시자 {URL}은 열려는 URL입니다(예: https://localhost:5001).
    • 이름 필드에 이름을 입력합니다. 예: Firefox Auth Testing.
    • 확인 단추를 선택합니다.
    • 앱 테스트를 반복할 때마다 브라우저 프로필을 선택할 필요가 없도록 하려면 기본값으로 설정 단추를 사용하여 프로필을 기본값으로 설정합니다.
    • 앱, 테스트 사용자 또는 공급자 구성을 변경할 때 IDE를 통해 브라우저를 닫습니다.

앱 업그레이드

개발 컴퓨터의 .NET Core SDK 또는 앱 내의 패키지 버전을 업그레이드하거나 앱 내 패키지 버전을 변경한 후 즉시 작동 중인 앱에서 오류가 발생할 수 있습니다. 경우에 따라 중요한 업그레이드를 수행할 때 일관되지 않은 패키지로 인해 응용 프로그램이 중단될 수 있습니다. 이러한 대부분의 문제는 다음 지침에 따라 수정할 수 있습니다.

  1. 명령 셸에서 dotnet nuget locals all --clear를 실행하여 로컬 시스템의 NuGet 패키지 캐시를 지웁니다.
  2. 프로젝트의 binobj 폴더를 삭제합니다.
  3. 프로젝트를 복원하고 다시 빌드합니다.
  4. 앱을 다시 배포하기 전에 서버의 배포 폴더에 있는 모든 파일을 삭제합니다.

참고

앱의 대상 프레임워크와 호환되지 않는 패키지 버전의 사용은 지원되지 않습니다. 패키지에 대한 자세한 내용은 NuGet 갤러리 또는 FuGet 패키지 탐색기를 사용하세요.

서버 앱 실행

호스트된 Blazor WebAssembly솔루션을 테스트하고 문제를 해결할 때 Server 프로젝트에서 앱을 실행하고 있는지 확인합니다. 예를 들어 Visual Studio에서 다음 방법 중 하나를 사용하여 앱을 시작하기 전에 솔루션 탐색기에서 서버 프로젝트가 강조 표시되어 있는지 확인합니다.

  • 실행 단추를 선택합니다.
  • 메뉴에서 디버그>디버깅 시작을 사용합니다.
  • F5키를 누릅니다.

사용자 검사

ASP.NET Core 프레임워크의 테스트 자산에는 Blazor WebAssembly 클라이언트 앱과 문제 해결에 유용할 수 있는 User 구성 요소가 있습니다. User 구성 요소는 앱에서 직접 사용하거나 추가 사용자 지정을 위한 기준으로 사용할 수 있습니다.

dotnet/aspnetcore GitHub 리포지토리User 테스트 구성 요소

참고

.NET 참조 원본의 설명서 링크는 일반적으로 다음 릴리스의 .NET을 위한 현재 개발을 나타내는 리포지토리의 기본 분기를 로드합니다. 특정 릴리스를 위한 태그를 선택하려면 Switch branches or tags(분기 또는 태그 전환) 드롭다운 목록을 사용합니다. 자세한 내용은 ASP.NET Core 소스 코드(dotnet/AspNetCore.Docs #26205)의 버전 태그를 선택하는 방법을 참조하세요.

JWT(JSON Web Token)의 콘텐츠 검사

JWT(JSON Web Token)를 디코딩하려면 Microsoft의 jwt.ms 도구를 사용합니다. UI의 값은 브라우저에 남겨지지 않습니다.

인코딩된 JWT 예제(표시를 위해 축약됨):

eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ilg1ZVhrNHh5b2pORnVtMWtsMll0djhkbE5QNC1j ... bQdHBHGcQQRbW7Wmo6SWYG4V_bU55Ug_PW4pLPr20tTS8Ct7_uwy9DWrzCMzpD-EiwT5IjXwlGX3IXVjHIlX50IVIydBoPQtadvT7saKo1G5Jmutgq41o-dmz6-yBMKV2_nXA25Q

Azure AAD B2C에 대해 인증하는 앱용 도구에 의해 디코딩된 JWT 예제:

{
  "typ": "JWT",
  "alg": "RS256",
  "kid": "X5eXk4xyojNFum1kl2Ytv8dlNP4-c57dO6QGTVBwaNk"
}.{
  "exp": 1610059429,
  "nbf": 1610055829,
  "ver": "1.0",
  "iss": "https://mysiteb2c.b2clogin.com/5cc15ea8-a296-4aa3-97e4-226dcc9ad298/v2.0/",
  "sub": "5ee963fb-24d6-4d72-a1b6-889c6e2c7438",
  "aud": "70bde375-fce3-4b82-984a-b247d823a03f",
  "nonce": "b2641f54-8dc4-42ca-97ea-7f12ff4af871",
  "iat": 1610055829,
  "auth_time": 1610055822,
  "idp": "idp.com",
  "tfp": "B2C_1_signupsignin"
}.[Signature]

추가 자료

AAD B2C에 앱을 등록하고 솔루션 만들기

테넌트 만들기

자습서: Azure Active Directory B2C 테넌트 만들기의 지침에 따라 AAD B2C 테넌트를 만듭니다. 사용할 테넌트를 만들거나 식별한 직후 이 문서로 돌아옵니다.

AAD B2C 인스턴스를 기록해 둡니다(예: 후행 슬래시를 포함하는 https://contoso.b2clogin.com/). 이 인스턴스는 Azure B2C 앱 등록의 스키마 및 호스트로, Azure Portal의 앱 등록 페이지에서 엔드포인트 창을 열어 찾을 수 있습니다.

서버 API 앱 등록

서버 API 앱을 위한 AAD B2C 앱을 등록합니다.

  1. Azure Portal에서 Azure Active Directory로 이동합니다. 사이드바에서 앱 등록을 선택합니다. 새 등록 단추를 선택합니다.
  2. 앱의 이름을 지정합니다(예: Blazor Server AAD B2C).
  3. 지원되는 계정 유형으로 다중 테넌트 옵션 모든 ID 공급자 또는 조직 디렉터리의 계정(사용자 흐름을 사용하여 사용자를 인증하는 경우)
  4. 이 시나리오에서는 ‘서버 API 앱’에 리디렉션 URI가 필요하지 않으므로 드롭다운이 으로 설정된 상태로 두고 리디렉션 URI를 입력하지 않습니다.
  5. 확인되지 않은 게시자 도메인을 사용하는 경우 권한>openid 및 offline_access 권한에 대한 관리자 동의 허용을 선택 취소했는지 확인합니다. 게시자 도메인이 확인된 경우에는 이 확인란이 표시되지 않습니다.
  6. 등록을 선택합니다.

다음과 같은 정보를 기록해 둡니다.

  • 서버 API 앱 애플리케이션(클라이언트) ID(예: 41451fa7-82d9-4673-8fa5-69eff5a761fd)
  • AAD 주/게시자/테넌트 도메인(예: contoso.onmicrosoft.com): 도메인은 Azure Portal에서 등록된 앱의 브랜딩 블레이드에 게시자 도메인으로 표시되어 있습니다.

API 표시에서:

  1. 범위 추가를 선택합니다.
  2. 저장 및 계속을 선택합니다.
  3. 범위 이름을 지정합니다(예: API.Access).
  4. 관리자 동의 표시 이름을 지정합니다(예: Access API).
  5. 관리자 동의 설명을 지정합니다(예: Allows the app to access server app API endpoints.).
  6. 상태사용으로 설정되었는지 확인합니다.
  7. 범위 추가를 선택합니다.

다음과 같은 정보를 기록해 둡니다.

  • 앱 ID URI(예: api://41451fa7-82d9-4673-8fa5-69eff5a761fd, https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd 또는 사용자가 지정한 사용자 지정 값)
  • 범위 이름(예: API.Access)

클라이언트 앱 등록

클라이언트 앱을 위한 AAD B2C 앱을 등록합니다.

  1. Azure Portal에서 Azure Active Directory로 이동합니다. 사이드바에서 앱 등록을 선택합니다. 새 등록 단추를 선택합니다.
  2. 앱의 이름을 지정합니다(예: Blazor 클라이언트 AAD B2C).
  3. 지원되는 계정 유형으로 다중 테넌트 옵션 모든 ID 공급자 또는 조직 디렉터리의 계정(사용자 흐름을 사용하여 사용자를 인증하는 경우)
  4. 리디렉션 URI 드롭다운은 으로 설정된 상태로 두고, 리디렉션 URI를 https://localhost/authentication/login-callback으로 지정합니다. Azure 기본 호스트에 대한 프로덕션 리디렉션 URI(예: azurewebsites.net) 또는 사용자 지정 도메인 호스트(예: contoso.com)를 알고 있는 경우 localhost 리디렉션 URI를 제공하는 동시에 프로덕션 리디렉션 URI를 추가할 수도 있습니다. 추가하는 프로덕션 리디렉션 URI에 비 :443 포트에 대한 포트 번호를 포함해야 합니다.
  5. 확인되지 않은 게시자 도메인을 사용하는 경우 권한>openid 및 offline_access 권한에 대한 관리자 동의 허용을 선택 취소했는지 확인합니다. 게시자 도메인이 확인된 경우에는 이 확인란이 표시되지 않습니다.
  6. 등록을 선택합니다.

참고

localhost AAD B2C 리디렉션 URI에 대한 포트 번호를 제공할 필요는 없습니다. 자세한 내용은 Redirect URI(회신 URL) 제한 사항: Localhost 예외(Azure 설명서)를 참조하세요.

애플리케이션(클라이언트) ID를 기록해 둡니다(예: 4369008b-21fa-427c-abaa-9b53bf58e538).

인증>플랫폼 구성>에서:

  1. https://localhost/authentication/login-callback리디렉션 URI가 있는지 확인합니다.
  2. 암시적 허용 섹션에서 액세스 토큰ID 토큰의 확인란을 선택합니다.
  3. 이 환경에서는 앱의 나머지 기본값을 그대로 사용해도 좋습니다.
  4. 저장 단추를 선택합니다.

API 사용 권한에서:

  1. 사용 권한 추가를 선택하고 내 API를 선택합니다.
  2. 이름 열에서 ‘서버 API 앱’을 선택합니다(예: Blazor Server AAD B2C).
  3. API 목록을 엽니다.
  4. API에 대한 액세스를 사용하도록 설정합니다(예: API.Access).
  5. 권한 추가를 선택합니다.
  6. {테넌트 이름}에 대한 관리자 동의 허용 단추를 선택합니다. 를 선택하여 확인합니다.

중요

앱 사용에 대한 동의가 사용자에게 위임되므로 API 권한 구성의 마지막 단계에서 테넌트에 관리자 동의를 부여할 권한이 없는 경우 다음 추가 단계를 수행해야 합니다.

  • 앱은 신뢰할 수 있는 게시자 도메인을 사용해야 합니다.
  • Azure Portal의 Server 앱 구성에서 API 공개를 선택합니다. 권한 있는 클라이언트 애플리케이션에서 클라이언트 애플리케이션 추가 단추를 선택합니다. Client 앱의 애플리케이션(클라이언트) ID를 추가합니다(예: 4369008b-21fa-427c-abaa-9b53bf58e538).

Home>Azure AD B2C>사용자 흐름에서 다음을 수행합니다.

가입 및 로그인 사용자 흐름 만들기

최소한 애플리케이션 클레임>표시 이름 사용자 특성을 선택하여 LoginDisplay 구성 요소(Shared/LoginDisplay.razor)의 context.User.Identity.Name을 채웁니다.

앱에 대해 만들어진 가입 및 로그인 사용자 흐름 이름을 기록해 둡니다(예: B2C_1_signupsignin).

앱 만들기

다음 명령에서 자리 표시자를 앞에서 기록해 둔 정보로 바꾸고 명령 셸에서 명령을 실행합니다.

dotnet new blazorwasm -au IndividualB2C --aad-b2c-instance "{AAD B2C INSTANCE}" --api-client-id "{SERVER API APP CLIENT ID}" --app-id-uri "{SERVER API APP ID URI}" --client-id "{CLIENT APP CLIENT ID}" --default-scope "{DEFAULT SCOPE}" --domain "{TENANT DOMAIN}" -ho -o {APP NAME} -ssp "{SIGN UP OR SIGN IN POLICY}"

경고

OIDC 앱 식별자의 형성을 중단하는 대시(-)를 앱 이름 {APP NAME}에 사용하지 마세요. Blazor WebAssembly 프로젝트 템플릿의 논리는 솔루션 구성에서 OIDC 앱 식별자에 대해 프로젝트 이름을 사용합니다. 파스칼식 대/소문자(BlazorSample) 또는 밑줄(Blazor_Sample)은 사용 가능한 대안입니다. 자세한 내용은 호스트된 Blazor WebAssembly 프로젝트 이름의 대시가 OIDC 보안 중단(dotnet/aspnetcore #35337)을 참조하세요.

자리표시자 Azure Portal 이름 예제
{AAD B2C INSTANCE} 인스턴스 https://contoso.b2clogin.com/
{APP NAME} BlazorSample
{CLIENT APP CLIENT ID} Client 앱의 애플리케이션(클라이언트) ID 4369008b-21fa-427c-abaa-9b53bf58e538
{DEFAULT SCOPE} 범위 이름 API.Access
{SERVER API APP CLIENT ID} 서버 API 앱의 애플리케이션(클라이언트) ID 41451fa7-82d9-4673-8fa5-69eff5a761fd
{SERVER API APP ID URI} 애플리케이션 ID URI† 41451fa7-82d9-4673-8fa5-69eff5a761fd
{SIGN UP OR SIGN IN POLICY} 가입/로그인 사용자 흐름 B2C_1_signupsignin1
{TENANT DOMAIN} 주/게시자/테넌트 도메인 contoso.onmicrosoft.com

†Blazor WebAssembly 템플릿은 dotnet new 명령에 전달된 앱 ID URI 인수에 api://의 구성표를 자동으로 추가합니다. {SERVER API APP ID URI} 자리 표시자의 앱 ID URI를 제공할 때 구성표가 api://인 경우 앞의 테이블에 나온 것처럼 인수에서 구성표(api://)를 제거하세요. 앱 ID URI가 사용자 지정 값이거나 다른 구성표(예를 들어 https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd와 유사한 확인되지 않은 게시자 도메인에 대해 https://)를 갖는 경우 기본 범위 URI를 수동으로 업데이트하고 템플릿이 Client 앱을 만든 후 api:// 구성표를 제거해야 합니다. 자세한 내용은 액세스 토큰 범위 섹션의 참고를 참조하세요. 이러한 시나리오를 해결하기 위해 ASP.NET Core의 이후 릴리스에서 Blazor WebAssembly 템플릿이 변경될 수 있습니다. 자세한 내용은 Double scheme for App ID URI with Blazor WASM template (hosted, single org) (dotnet/aspnetcore #27417)을 참조하세요.

-o|--output 옵션으로 지정된 출력 위치는 프로젝트 폴더가 없는 경우 폴더를 하나 만들고 앱 이름의 일부가 됩니다. OIDC 앱 식별자의 형성을 중단하는 대시(-)를 앱 이름에 사용하지 마세요(앞에 나온 경고 참조).

참고

Blazor WebAssembly 프로젝트 템플릿에서 호스티된 Blazor WebAssembly 솔루션에 설정한 범위에서는 앱 ID URI 호스트가 반복될 수 있습니다. Client 앱의 Program.cs에서 DefaultAccessTokenScopes 컬렉션에 대해 구성된 범위가 올바른지 확인합니다.

Server 앱 구성

이 섹션은 솔루션의 Server 앱에 적용됩니다.

인증 패키지

ASP.NET Core Web API에 대한 호출의 인증 및 권한 부여 지원은 Microsoft.AspNetCore.Authentication.AzureADB2C.UI 패키지에서 제공합니다.

참고

.NET 앱에 패키지를 추가하는 지침은 패키지 사용 워크플로(NuGet 설명서)에서 패키지 설치 및 관리 아래의 문서를 참조하세요. NuGet.org에서 올바른 패키지 버전을 확인합니다.

인증 서비스 지원

AddAuthentication 메서드는 앱 내에서 인증 서비스를 설정하고 JWT 전달자 처리기를 기본 인증 메서드로 구성합니다. AddAzureADB2CBearer 메서드는 JWT 전달자 처리기에서 Azure Active Directory B2C에서 내보낸 토큰의 유효성을 검사하는 데 필요한 특정 매개 변수를 설정합니다.

services.AddAuthentication(AzureADB2CDefaults.BearerAuthenticationScheme)
    .AddAzureADB2CBearer(options => Configuration.Bind("AzureAdB2C", options));

UseAuthenticationUseAuthorization은 다음을 수행합니다.

  • 앱이 수신 요청에 대해 토큰의 구문 분석 및 유효성 검사를 시도하도록 합니다.
  • 올바른 자격 증명 없이 보호된 리소스에 액세스하려는 요청은 모두 실패하도록 합니다.
app.UseAuthentication();
app.UseAuthorization();

User.Identity.Name

기본적으로 User.Identity.Name은 채워지지 않습니다.

name 클레임 유형에서 값을 받도록 앱을 구성하려면 다음을 수행합니다.

앱 설정

appsettings.json 파일은 액세스 토큰의 유효성을 검사하는 데 사용되는 JWT 전달자 처리기를 구성하기 위한 옵션을 포함합니다.

{
  "AzureAdB2C": {
    "Instance": "https://{TENANT}.b2clogin.com/",
    "ClientId": "{SERVER API APP CLIENT ID}",
    "Domain": "{TENANT DOMAIN}",
    "SignUpSignInPolicyId": "{SIGN UP OR SIGN IN POLICY}"
  }
}

예:

{
  "AzureAdB2C": {
    "Instance": "https://contoso.b2clogin.com/",
    "ClientId": "41451fa7-82d9-4673-8fa5-69eff5a761fd",
    "Domain": "contoso.onmicrosoft.com",
    "SignUpSignInPolicyId": "B2C_1_signupsignin1",
  }
}

WeatherForecast 컨트롤러

WeatherForecast 컨트롤러(Controllers/WeatherForecastController.cs)는 컨트롤러에 적용된 [Authorize] 특성으로 보호된 API를 노출합니다. 다음과 같은 사항을 이해하는 것이 중요합니다.

  • 이 API 컨트롤러의 [Authorize] 특성은 무단 액세스로부터 이 API를 보호하는 유일한 항목입니다.
  • Blazor WebAssembly 앱에서 사용되는 [Authorize] 특성은 앱이 올바르게 작동하려면 사용자에게 권한이 부여되어야 한다는 힌트로만 앱에 제공됩니다.
[Authorize]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    [HttpGet]
    public IEnumerable<WeatherForecast> Get()
    {
        ...
    }
}

Client 앱 구성

이 섹션은 솔루션의 Client 앱에 적용됩니다.

인증 패키지

앱이 개별 B2C 계정을 사용하도록 만들어진 경우(IndividualB2C) 해당 앱은 자동으로 Microsoft 인증 라이브러리(Microsoft.Authentication.WebAssembly.Msal)에 대한 패키지 참조를 받습니다. 패키지는 앱이 사용자를 인증하고 보호된 API를 호출하는 데 사용할 토큰을 가져올 수 있도록 지원하는 기본 형식 세트를 제공합니다.

앱에 인증을 추가하는 경우에는 Microsoft.Authentication.WebAssembly.Msal 패키지를 앱에 수동으로 추가합니다.

참고

.NET 앱에 패키지를 추가하는 지침은 패키지 사용 워크플로(NuGet 설명서)에서 패키지 설치 및 관리 아래의 문서를 참조하세요. NuGet.org에서 올바른 패키지 버전을 확인합니다.

Microsoft.Authentication.WebAssembly.Msal 패키지는 타동적으로 Microsoft.AspNetCore.Components.WebAssembly.Authentication 패키지를 앱에 추가합니다.

인증 서비스 지원

서버 프로젝트로 요청을 전송할 때 액세스 토큰을 포함하는 HttpClient 인스턴스에 대한 지원이 추가됩니다.

Program.cs:

builder.Services.AddHttpClient("{APP ASSEMBLY}.ServerAPI", client => 
    client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
    .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();

builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>()
    .CreateClient("{APP ASSEMBLY}.ServerAPI"));

자리 표시자 {APP ASSEMBLY}는 앱의 어셈블리 이름입니다(예: BlazorSample.Client).

사용자 인증에 대한 지원은 Microsoft.Authentication.WebAssembly.Msal 패키지에서 제공하는 AddMsalAuthentication 확장 메서드를 통해 서비스 컨테이너에 등록됩니다. 이 메서드는 앱이 IP(Identity 공급자)와 상호 작용하는 데 필요한 서비스를 설정합니다.

Program.cs:

builder.Services.AddMsalAuthentication(options =>
{
    builder.Configuration.Bind("AzureAdB2C", options.ProviderOptions.Authentication);
    options.ProviderOptions.DefaultAccessTokenScopes.Add("{SCOPE URI}");
});

AddMsalAuthentication 메서드는 콜백을 받아서 앱을 인증하는 데 필요한 매개 변수를 구성합니다. 앱을 구성하는 데 필요한 값은 앱을 등록할 때 Azure Portal AAD 구성에서 얻을 수 있습니다.

구성은 wwwroot/appsettings.json 파일에서 제공합니다.

{
  "AzureAdB2C": {
    "Authority": "{AAD B2C INSTANCE}{TENANT DOMAIN}/{SIGN UP OR SIGN IN POLICY}",
    "ClientId": "{CLIENT APP CLIENT ID}",
    "ValidateAuthority": false
  }
}

예:

{
  "AzureAdB2C": {
    "Authority": "https://contoso.b2clogin.com/contoso.onmicrosoft.com/B2C_1_signupsignin1",
    "ClientId": "4369008b-21fa-427c-abaa-9b53bf58e538",
    "ValidateAuthority": false
  }
}

액세스 토큰 범위

기본 액세스 토큰 범위는 다음과 같은 액세스 토큰 범위 목록을 나타냅니다.

  • 기본적으로 로그인 요청에 포함되어 있음.
  • 인증 직후에 액세스 토큰을 프로비저닝하는 데 사용됨.

모든 범위는 Azure Active Directory 규칙에 따라 동일한 앱에 속해 있어야 합니다. 필요에 따라 추가 API 앱에 대한 추가 범위가 추가될 수 있습니다.

builder.Services.AddMsalAuthentication(options =>
{
    ...
    options.ProviderOptions.DefaultAccessTokenScopes.Add("{SCOPE URI}");
});

참고

Blazor WebAssembly 템플릿은 dotnet new 명령에 전달된 앱 ID URI 인수에 api://의 구성표를 자동으로 추가합니다. Blazor 프로젝트 템플릿에서 앱을 생성할 때 기본 액세스 토큰 범위의 값이 Azure Portal에 제공한 올바른 사용자 지정 앱 ID URI 값 또는 다음 형식 중 하나인 값을 사용하는지 확인합니다.

  • 디렉터리의 게시자 도메인을 신뢰할 수 있는 경우 기본 액세스 토큰 범위는 일반적으로 다음 예제와 비슷한 값입니다. 여기서 API.Access는 기본 범위 이름입니다.

    options.ProviderOptions.DefaultAccessTokenScopes.Add(
        "api://41451fa7-82d9-4673-8fa5-69eff5a761fd/API.Access");
    

    이중 구성표(api://api://...)의 값을 검사합니다. 이중 구성표가 있는 경우 값에서 첫 번째 api:// 구성표를 제거합니다.

  • 디렉터리의 게시자 도메인을 신뢰할 수 없는 경우 기본 액세스 토큰 범위는 일반적으로 다음 예제와 비슷한 값입니다. 여기서 API.Access는 기본 범위 이름입니다.

    options.ProviderOptions.DefaultAccessTokenScopes.Add(
        "https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd/API.Access");
    

    추가 api:// 구성표(api://https://contoso.onmicrosoft.com/...)의 값을 검사합니다. 추가 api:// 구성표가 있는 경우 값에서 api:// 구성표를 제거합니다.

이러한 시나리오를 해결하기 위해 ASP.NET Core의 이후 릴리스에서 Blazor WebAssembly 템플릿이 변경될 수 있습니다. 자세한 내용은 Double scheme for App ID URI with Blazor WASM template (hosted, single org) (dotnet/aspnetcore #27417)을 참조하세요.

AdditionalScopesToConsent를 사용하여 추가 범위를 지정합니다.

options.ProviderOptions.AdditionalScopesToConsent.Add("{ADDITIONAL SCOPE URI}");

자세한 내용은 ‘추가 시나리오’ 문서의 다음 섹션을 참조하세요.

Imports 파일

Microsoft.AspNetCore.Components.Authorization 네임스페이스는 _Imports.razor 파일을 통해 앱 전체에서 사용할 수 있게 됩니다.

@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Microsoft.JSInterop
@using {APPLICATION ASSEMBLY}.Client
@using {APPLICATION ASSEMBLY}.Client.Shared

인덱스 페이지

인덱스 페이지(wwwroot/index.html)는 JavaScript로 AuthenticationService를 정의하는 스크립트를 포함합니다. AuthenticationService는 OIDC 프로토콜의 하위 수준 세부 정보를 처리합니다. 앱은 내부적으로 스크립트에 정의된 메서드를 호출하여 인증 작업을 수행합니다.

<script src="_content/Microsoft.Authentication.WebAssembly.Msal/AuthenticationService.js"></script>

App 구성 요소

App 구성 요소(App.razor)는 Blazor Server 앱에 있는 App 구성 요소와 비슷합니다.

  • CascadingAuthenticationState 구성 요소는 앱의 나머지 부분에 AuthenticationState를 노출하는 것을 관리합니다.
  • AuthorizeRouteView 구성 요소는 현재 사용자가 지정된 페이지에 액세스할 수 있는 권한이 부여받았는지 확인하고 그러지 않은 경우 RedirectToLogin 구성 요소를 렌더링합니다.
  • RedirectToLogin 구성 요소는 권한 없는 사용자를 로그인 페이지로 리디렉션하는 기능을 관리합니다.

ASP.NET Core 릴리스 간 프레임워크 변경으로 인해 App 구성 요소의 Razor 변경 내용(App.razor)은 이 섹션에 표시되지 않습니다. 지정된 릴리스의 구성 요소의 변경 내용을 검사하려면 다음 방법 중 하나를 사용합니다.

  • 사용하려는 ASP.NET Core 버전의 기본 Blazor WebAssembly 프로젝트 템플릿에서 인증을 위해 프로비전된 앱을 만듭니다. 생성된 앱에서 App 구성 요소(App.razor)를 검사합니다.

  • 참조 소스에서 App 구성 요소(App.razor)를 검사합니다.

    참고

    .NET 참조 원본의 설명서 링크는 일반적으로 다음 릴리스의 .NET을 위한 현재 개발을 나타내는 리포지토리의 기본 분기를 로드합니다. 특정 릴리스를 위한 태그를 선택하려면 Switch branches or tags(분기 또는 태그 전환) 드롭다운 목록을 사용합니다. 자세한 내용은 ASP.NET Core 소스 코드(dotnet/AspNetCore.Docs #26205)의 버전 태그를 선택하는 방법을 참조하세요.

RedirectToLogin 구성 요소

RedirectToLogin 구성 요소(Shared/RedirectToLogin.razor)는 다음을 수행합니다.

  • 로그인 페이지로의 권한 없는 사용자 리디렉션을 관리합니다.
  • 사용자가 인증에 성공하면 해당 페이지로 되돌아올 수 있도록 사용자가 액세스하려고 하는 현재 URL을 유지합니다.
@inject NavigationManager Navigation
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@code {
    protected override void OnInitialized()
    {
        Navigation.NavigateTo(
            $"authentication/login?returnUrl={Uri.EscapeDataString(Navigation.Uri)}");
    }
}

LoginDisplay 구성 요소

LoginDisplay 구성 요소(Shared/LoginDisplay.razor)는 MainLayout 구성 요소(Shared/MainLayout.razor)에서 렌더링되고 다음 동작을 관리합니다.

  • 인증된 사용자의 경우:
    • 현재 사용자 이름을 표시합니다.
    • 앱에서 로그아웃하는 단추를 제공합니다.
  • 익명 사용자의 경우, 로그인 옵션을 제공합니다.
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject NavigationManager Navigation
@inject SignOutSessionStateManager SignOutManager

<AuthorizeView>
    <Authorized>
        Hello, @context.User.Identity.Name!
        <button class="nav-link btn btn-link" @onclick="BeginLogout">
            Log out
        </button>
    </Authorized>
    <NotAuthorized>
        <a href="authentication/login">Log in</a>
    </NotAuthorized>
</AuthorizeView>

@code {
    private async Task BeginLogout(MouseEventArgs args)
    {
        await SignOutManager.SetSignOutState();
        Navigation.NavigateTo("authentication/logout");
    }
}

Authentication 구성 요소

Authentication 구성 요소에 의해 생성된 페이지(Pages/Authentication.razor)는 다른 인증 단계를 처리하는 데 필요한 경로를 정의합니다.

RemoteAuthenticatorView 구성 요소는 다음과 같습니다.

@page "/authentication/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication

<RemoteAuthenticatorView Action="@Action" />

@code {
    [Parameter]
    public string Action { get; set; }
}

FetchData 구성 요소

FetchData 구성 요소는 다음을 수행하는 방법을 보여 줍니다.

  • 액세스 토큰을 프로비저닝합니다.
  • 액세스 토큰을 사용하여 ‘서버’ 앱에서 보호된 리소스 API를 호출합니다.

@attribute [Authorize] 지시문은 사용자가 이 구성 요소에 액세스하기 위해 권한을 부여받아야 한다는 것을 Blazor WebAssembly 권한 부여 시스템에 나타냅니다. Client 앱에 특성이 있으면 서버에 있는 API가 적절한 자격 증명 없이 호출되는 것을 방지하지 않습니다. 또한 Server 앱은 적절한 엔드포인트에서 [Authorize]를 사용하여 올바로 보호해야 합니다.

IAccessTokenProvider.RequestAccessToken은 API를 호출하는 요청에 추가할 수 있는 액세스 토큰을 요청하는 작업을 처리합니다. 토큰이 캐시되었거나 서비스에서 사용자 개입 없이 새 액세스 토큰을 프로비저닝할 수 있으면 토큰 요청이 성공합니다. 그러지 않으면 토큰 요청이 실패하고 AccessTokenNotAvailableExceptiontry-catch 문에 catch됩니다.

요청에 포함할 실제 토큰을 가져오려면 앱에서 tokenResult.TryGetToken(out var token)을 호출하여 요청이 성공했는지 확인해야 합니다.

요청이 성공하면 토큰 변수가 액세스 토큰으로 채워집니다. 토큰의 AccessToken.Value 속성은 Authorization 요청 헤더에 포함할 리터럴 문자열을 노출합니다.

사용자 개입 없이 토큰을 프로비저닝할 수 없어 요청이 실패한 경우 토큰 결과에 리디렉션 URL이 포함됩니다. 이 URL로 이동하면 사용자가 로그인 페이지로 이동하고 인증 성공 후 현재 페이지로 돌아옵니다.

@page "/fetchdata"
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using {APP NAMESPACE}.Shared
@attribute [Authorize]
@inject HttpClient Http

...

@code {
    private WeatherForecast[] forecasts;

    protected override async Task OnInitializedAsync()
    {
        try
        {
            forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
    }
}

앱 실행

서버 프로젝트에서 앱을 실행합니다. Visual Studio를 사용하는 경우 다음 중 하나를 수행합니다.

  • 도구 모음의 시작 프로젝트 드롭다운 목록을 ‘서버 API 앱’으로 설정하고 실행 단추를 선택합니다.
  • 솔루션 탐색기에서 서버 프로젝트를 선택하고 도구 모음에서 실행 단추를 선택하거나 디버그 메뉴에서 앱을 시작합니다.

UserManagerSignInManager

서버 앱에 다음이 필요한 경우 사용자 ID 클레임 유형을 설정합니다.

ASP.NET Core 6.0 이상의 Program.cs에서 다음을 수행합니다.

using System.Security.Claims;

...

builder.Services.Configure<IdentityOptions>(options => 
    options.ClaimsIdentity.UserIdClaimType = ClaimTypes.NameIdentifier);

ASP.NET Core 6.0 이전 버전의 Startup.ConfigureServices에서:

using System.Security.Claims;

...

services.Configure<IdentityOptions>(options => 
    options.ClaimsIdentity.UserIdClaimType = ClaimTypes.NameIdentifier);

다음 WeatherForecastControllerGet 메서드가 호출될 때 UserName을 로깅합니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using BlazorSample.Server.Models;
using BlazorSample.Shared;

namespace BlazorSample.Server.Controllers
{
    [Authorize]
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        private readonly UserManager<ApplicationUser> userManager;

        private static readonly string[] Summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", 
            "Balmy", "Hot", "Sweltering", "Scorching"
        };

        private readonly ILogger<WeatherForecastController> logger;

        public WeatherForecastController(ILogger<WeatherForecastController> logger, 
            UserManager<ApplicationUser> userManager)
        {
            this.logger = logger;
            this.userManager = userManager;
        }

        [HttpGet]
        public async Task<IEnumerable<WeatherForecast>> Get()
        {
            var rng = new Random();

            var user = await userManager.GetUserAsync(User);

            if (user != null)
            {
                logger.LogInformation($"User.Identity.Name: {user.UserName}");
            }

            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = rng.Next(-20, 55),
                Summary = Summaries[rng.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }
}

이전 예제에서는 다음을 수행합니다.

  • Server 프로젝트의 네임스페이스는 BlazorSample.Server입니다.
  • Shared 프로젝트의 네임스페이스는 BlazorSample.Shared입니다.

사용자 지정 사용자 흐름

Microsoft 인증 라이브러리(Microsoft.Authentication.WebAssembly.Msal, NuGet 패키지)는 기본적으로 AAD B2C 사용자 흐름을 지원하지 않습니다. 개발자 코드에서 사용자 지정 사용자 흐름을 만듭니다.

사용자 지정 사용자 흐름의 챌린지를 작성하는 방법에 대한 자세한 내용은 Azure Active Directory B2C의 사용자 흐름을 참조하세요.

문제 해결

일반 오류

  • 앱 또는 IP(Identity 공급자)의 잘못된 구성

    가장 일반적인 오류는 잘못된 구성으로 인해 발생합니다. 다음은 몇 가지 예제입니다.

    • 시나리오의 요구 사항에 따라, 누락되거나 잘못된 권한, 인스턴스, 테넌트 ID, 테넌트 도메인, 클라이언트 ID 또는 리디렉션 URI 때문에 앱에서 클라이언트를 인증하지 못합니다.
    • 액세스 토큰 범위가 잘못되어 클라이언트가 서버 웹 API 엔드포인트에 액세스하지 못합니다.
    • 서버 API 권한이 잘못되거나 누락되어 클라이언트가 서버 웹 API 엔드포인트에 액세스할 수 없습니다.
    • Identity 공급자 앱 등록의 리디렉션 URI에 구성된 것과 다른 포트에서 앱을 실행합니다.

    이 문서 지침의 구성 섹션에서는 올바른 구성의 예를 보여 줍니다. 앱 및 IP 구성을 찾는 문서의 각 섹션을 주의 깊게 확인하세요.

    구성이 올바르게 표시되면 다음을 수행합니다.

    • 애플리케이션 로그를 분석합니다.

    • 브라우저의 개발자 도구를 사용하여 클라이언트 앱과 IP 또는 서버 앱 간의 네트워크 트래픽을 검사합니다. 종종 정확한 오류 메시지 또는 문제의 원인에 대한 단서가 있는 메시지가 요청을 수행한 후 IP 또는 서버 앱에 의해 클라이언트로 반환됩니다. 개발자 도구 지침은 다음 문서에서 확인할 수 있습니다.

    • 문제가 발생한 위치에 따라 클라이언트를 인증하거나 서버 웹 API에 액세스하는 데 사용되는 JWT(JSON Web Token)의 콘텐츠를 디코딩합니다. 자세한 내용은 JWT(JSON Web Token)의 콘텐츠 검사를 참조하세요.

    문서 작업 팀은 설명서 피드백 및 문서의 버그에 응답하지만(이 페이지의 피드백 섹션에서 문제 열기) 제품 지원을 제공할 수 없습니다. 앱 문제 해결을 지원하기 위해 몇 가지 퍼블릭 지원 포럼을 사용할 수 있습니다. 다음 방법을 사용하는 것이 좋습니다.

    위의 포럼은 Microsoft에서 소유하거나 관리하지 않습니다.

    중요하지 않고 보안이나 기밀이 아니며 재현 가능한 프레임워크 버그 보고서의 경우 ASP.NET Core 제품 단위에서 문제를 여세요. 문제의 원인을 철저하게 조사했으며 자신의 노력과 퍼블릭 지원 포럼에서 커뮤니티의 도움을 받아도 해결할 수 없는 경우에만 제품 단위에서 문제를 열고 그전에는 열지 마세요. 제품 단위는 단순한 구성 오류 또는 타사 서비스와 관련된 사용 사례로 인해 손상된 개별 앱의 문제를 해결할 수 없습니다. 신고서가 본질적으로 중요하거나 기밀이거나 공격자가 악용할 수 있는 제품의 잠재적인 보안 결함을 설명하는 경우 보안 문제 및 버그 신고(dotnet/aspnetcore GitHub 리포지토리)를 참조하세요.

  • AAD에 대한 권한이 없는 클라이언트

    정보: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2] 권한 부여에 실패했습니다. 다음 요구 사항이 충족되지 않았습니다. DenyAnonymousAuthorizationRequirement: 인증된 사용자가 필요합니다.

    AAD에서 로그인 콜백 오류:

    • 오류: unauthorized_client
    • 설명: AADB2C90058: The provided application is not configured to allow public clients.

    오류를 해결하려면:

    1. Azure Portal에서 앱의 매니페스트에 액세스합니다.
    2. allowPublicClient 특성null 또는 true로 설정합니다.

Cookie 및 사이트 데이터

Cookie 및 사이트 데이터가 앱을 업데이트할 때에도 유지되어 테스트 및 문제 해결에 방해가 될 수 있습니다. 앱 코드를 변경하거나 공급자를 사용하여 사용자 계정을 변경하거나 공급자 앱 구성을 변경하는 경우 다음을 지우세요.

  • 사용자 로그인 cookie
  • 앱 cookie
  • 캐시되고 저장된 사이트 데이터

남겨진 cookie 및 사이트 데이터로 인해 테스트 및 문제 해결이 지장을 받지 않도록 하려면 다음을 수행합니다.

  • 브라우저 구성
    • 브라우저에서 브라우저를 닫을 때마다 모든 cookie 및 사이트 데이터를 삭제하도록 구성할 수 있는지 테스트합니다.
    • 앱, 테스트 사용자 또는 공급자 구성을 변경할 때 수동으로 또는 IDE를 통해 브라우저를 닫습니다.
  • 사용자 지정 명령을 사용하여 Visual Studio에서 시크릿 또는 프라이빗 모드로 브라우저를 엽니다.
    • Visual Studio의 실행 단추를 통해 브라우저 선택 대화 상자를 엽니다.
    • 추가 단추를 선택합니다.
    • 프로그램 필드에서 브라우저의 경로를 제공합니다. 다음 실행 파일 경로는 Windows 10에서 일반적인 설치 위치입니다. 브라우저가 다른 위치에 설치되어 있거나 Windows 10을 사용하지 않는 경우 브라우저 실행 파일의 경로를 제공합니다.
      • Microsoft Edge: C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe
      • Google Chrome: C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
      • Mozilla Firefox: C:\Program Files\Mozilla Firefox\firefox.exe
    • 인수 필드에 브라우저에서 시크릿 또는 프라이빗 모드로 열 때 사용하는 명령줄 옵션을 제공합니다. 일부 브라우저에는 앱의 URL이 필요합니다.
      • Microsoft Edge: -inprivate을 사용하십시오.
      • Google Chrome: --incognito --new-window {URL}를 사용합니다. 여기서 자리 표시자 {URL}은 열려는 URL입니다(예: https://localhost:5001).
      • Mozilla Firefox: -private -url {URL}을 사용합니다. 여기서 자리 표시자 {URL}은 열려는 URL입니다(예: https://localhost:5001).
    • 이름 필드에 이름을 입력합니다. 예: Firefox Auth Testing.
    • 확인 단추를 선택합니다.
    • 앱 테스트를 반복할 때마다 브라우저 프로필을 선택할 필요가 없도록 하려면 기본값으로 설정 단추를 사용하여 프로필을 기본값으로 설정합니다.
    • 앱, 테스트 사용자 또는 공급자 구성을 변경할 때 IDE를 통해 브라우저를 닫습니다.

앱 업그레이드

개발 컴퓨터의 .NET Core SDK 또는 앱 내의 패키지 버전을 업그레이드하거나 앱 내 패키지 버전을 변경한 후 즉시 작동 중인 앱에서 오류가 발생할 수 있습니다. 경우에 따라 중요한 업그레이드를 수행할 때 일관되지 않은 패키지로 인해 응용 프로그램이 중단될 수 있습니다. 이러한 대부분의 문제는 다음 지침에 따라 수정할 수 있습니다.

  1. 명령 셸에서 dotnet nuget locals all --clear를 실행하여 로컬 시스템의 NuGet 패키지 캐시를 지웁니다.
  2. 프로젝트의 binobj 폴더를 삭제합니다.
  3. 프로젝트를 복원하고 다시 빌드합니다.
  4. 앱을 다시 배포하기 전에 서버의 배포 폴더에 있는 모든 파일을 삭제합니다.

참고

앱의 대상 프레임워크와 호환되지 않는 패키지 버전의 사용은 지원되지 않습니다. 패키지에 대한 자세한 내용은 NuGet 갤러리 또는 FuGet 패키지 탐색기를 사용하세요.

서버 앱 실행

호스트된 Blazor WebAssembly솔루션을 테스트하고 문제를 해결할 때 Server 프로젝트에서 앱을 실행하고 있는지 확인합니다. 예를 들어 Visual Studio에서 다음 방법 중 하나를 사용하여 앱을 시작하기 전에 솔루션 탐색기에서 서버 프로젝트가 강조 표시되어 있는지 확인합니다.

  • 실행 단추를 선택합니다.
  • 메뉴에서 디버그>디버깅 시작을 사용합니다.
  • F5키를 누릅니다.

사용자 검사

ASP.NET Core 프레임워크의 테스트 자산에는 Blazor WebAssembly 클라이언트 앱과 문제 해결에 유용할 수 있는 User 구성 요소가 있습니다. User 구성 요소는 앱에서 직접 사용하거나 추가 사용자 지정을 위한 기준으로 사용할 수 있습니다.

dotnet/aspnetcore GitHub 리포지토리User 테스트 구성 요소

참고

.NET 참조 원본의 설명서 링크는 일반적으로 다음 릴리스의 .NET을 위한 현재 개발을 나타내는 리포지토리의 기본 분기를 로드합니다. 특정 릴리스를 위한 태그를 선택하려면 Switch branches or tags(분기 또는 태그 전환) 드롭다운 목록을 사용합니다. 자세한 내용은 ASP.NET Core 소스 코드(dotnet/AspNetCore.Docs #26205)의 버전 태그를 선택하는 방법을 참조하세요.

JWT(JSON Web Token)의 콘텐츠 검사

JWT(JSON Web Token)를 디코딩하려면 Microsoft의 jwt.ms 도구를 사용합니다. UI의 값은 브라우저에 남겨지지 않습니다.

인코딩된 JWT 예제(표시를 위해 축약됨):

eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ilg1ZVhrNHh5b2pORnVtMWtsMll0djhkbE5QNC1j ... bQdHBHGcQQRbW7Wmo6SWYG4V_bU55Ug_PW4pLPr20tTS8Ct7_uwy9DWrzCMzpD-EiwT5IjXwlGX3IXVjHIlX50IVIydBoPQtadvT7saKo1G5Jmutgq41o-dmz6-yBMKV2_nXA25Q

Azure AAD B2C에 대해 인증하는 앱용 도구에 의해 디코딩된 JWT 예제:

{
  "typ": "JWT",
  "alg": "RS256",
  "kid": "X5eXk4xyojNFum1kl2Ytv8dlNP4-c57dO6QGTVBwaNk"
}.{
  "exp": 1610059429,
  "nbf": 1610055829,
  "ver": "1.0",
  "iss": "https://mysiteb2c.b2clogin.com/5cc15ea8-a296-4aa3-97e4-226dcc9ad298/v2.0/",
  "sub": "5ee963fb-24d6-4d72-a1b6-889c6e2c7438",
  "aud": "70bde375-fce3-4b82-984a-b247d823a03f",
  "nonce": "b2641f54-8dc4-42ca-97ea-7f12ff4af871",
  "iat": 1610055829,
  "auth_time": 1610055822,
  "idp": "idp.com",
  "tfp": "B2C_1_signupsignin"
}.[Signature]

추가 자료