다음을 통해 공유


Microsoft Entra ID를 사용하여 ASP.NET Core Blazor Web App 보호

이 문서에서는 Microsoft ID 플랫폼과 Microsoft 웹 패키지를 사용하여 Microsoft Entra ID를 샘플 앱으로 보호하는 방법을 설명합니다.

이 버전의 문서에서는 BFF(프런트 엔드) 패턴채택하지 않고 Entra를 구현하는 것에 대해 설명합니다. BFF 패턴은 외부 서비스에 대해 인증된 요청을 만드는 데 유용합니다. 앱의 사양에서 BFF 패턴 채택을 요구하는 경우 문서 버전 선택기를 BFF 패턴 변경합니다.

다음 사양이 적용됩니다.

  • 전역 대화형 작업()과 함께 자동 렌더링 모드를 사용합니다.
  • 서버 프로젝트는 서버 측 인증 상태 공급자를 추가하기 위해 AddAuthenticationStateSerialization을(를) 호출하며, 이 공급자는 PersistentComponentState을 사용하여 인증 상태를 클라이언트로 전달합니다. 클라이언트는 서버에서 전달한 인증 상태를 역직렬화하고 사용하기 위해 호출 AddAuthenticationStateDeserialization 합니다. 인증 상태는 WebAssembly 애플리케이션의 수명 동안 고정됩니다.
  • 앱은 Microsoft 웹 패키지에 기반해 Identity를 사용합니다.
  • 자동 비대화형 토큰 새로 고침은 프레임워크에서 관리됩니다.
  • 앱은 서버 쪽 및 클라이언트 쪽 서비스 추상화로 생성된 날씨 데이터를 표시합니다.
    • 서버에서 Weather 구성 요소를 렌더링하여 날씨 데이터를 표시할 때 구성 요소는 서버에서 ServerWeatherForecaster 해당 구성 요소를 사용하여 웹 API 호출이 아닌 날씨 데이터를 직접 가져옵니다.
    • Weather 구성 요소가 클라이언트에서 렌더링될 때 구성 요소는 미리 구성된 ClientWeatherForecaster (클라이언트 프로젝트 파일)를 사용하여 날씨 데이터에 대한 서버 프로젝트의 HttpClient 최소 API(Program)에 대한 웹 API 호출을 만드는 서비스 구현을 사용합니다/weather-forecast. 최소 API 엔드포인트는 클래스에서 ServerWeatherForecaster 날씨 데이터를 가져와서 구성 요소에서 렌더링하기 위해 클라이언트에 반환합니다.

샘플 앱

샘플 앱은 다음 두 개의 프로젝트로 구성됩니다.

  • BlazorWebAppEntra: 날씨 데이터를 위한 예제 Blazor Web App 엔드포인트가 포함된 서버 측 프로젝트입니다.
  • BlazorWebAppEntra.Client: Blazor Web App 클라이언트 측 프로젝트입니다.

다음 링크를 사용하여 Blazor 샘플 리포지토리의 최신 버전 폴더를 통해 샘플에 액세스합니다. 샘플은 .NET 9 이상용 BlazorWebAppEntra 폴더에 있습니다.

샘플 코드 보기 및 다운로드(다운로드 방법)

서버 쪽 Blazor Web App 프로젝트(BlazorWebAppEntra)

BlazorWebAppEntra 프로젝트는 Blazor Web App의 서버 쪽 프로젝트입니다.

이 파일은 BlazorWebAppEntra.http 날씨 데이터 요청을 테스트하는 데 사용할 수 있습니다. 엔드포인트를 BlazorWebAppEntra 테스트하려면 프로젝트를 실행해야 하며 엔드포인트는 파일로 하드 코딩됩니다. 자세한 내용은 Visual Studio 2022에서 .http 파일 사용을 참조 하세요.

클라이언트 쪽 Blazor Web App 프로젝트(BlazorWebAppEntra.Client)

BlazorWebAppEntra.Client 프로젝트는 Blazor Web App의 클라이언트 측 프로젝트입니다.

클라이언트 쪽 렌더링 중에 사용자가 로그인하거나 로그아웃해야 하는 경우 전체 페이지 다시 로드가 시작됩니다.

구성

이 섹션에서는 샘플 앱을 구성하는 방법을 설명합니다.

AddMicrosoftIdentityWebApp Microsoft Identity Web(Microsoft.Identity.WebNuGet 패키지, API 설명서)는 서버 프로젝트의 AzureAd 파일에 있는 appsettings.json 섹션에 의해 구성됩니다.

Entra 또는 Azure 포털의 앱 등록에서 리디렉션 URI가 있는 웹 플랫폼 구성을 사용하세요. 포트는 필요하지 않습니다. 암시적 권한 부여 및 하이브리드 흐름에서 ID 토큰 및 액세스 토큰이 선택되지 않은지 확인합니다. OpenID Connect 처리기는 권한 부여 엔드포인트에서 반환된 코드를 사용하여 적절한 토큰을 자동으로 요청합니다.

앱 구성

서버 프로젝트의 앱 설정 파일(appsettings.json)에서 앱의 AzureAd 섹션 구성을 제공합니다. Entra 또는 Azure Portal의 앱 등록에서 애플리케이션(클라이언트) ID, 테넌트(게시자) 도메인 및 디렉터리(테넌트) ID를 가져옵니다.

"AzureAd": {
  "CallbackPath": "/signin-oidc",
  "ClientId": "{CLIENT ID}",
  "Domain": "{DOMAIN}",
  "Instance": "https://login.microsoftonline.com/",
  "ResponseType": "code",
  "TenantId": "{TENANT ID}"
},

이전 예제에 포함된 자리 표시자:

  • {CLIENT ID}: 애플리케이션(클라이언트) ID입니다.
  • {DOMAIN}: 테넌트(게시자) 도메인입니다.
  • {TENANT ID}: 디렉터리(테넌트) ID입니다.

예시:

"AzureAd": {
  "CallbackPath": "/signin-oidc",
  "ClientId": "00001111-aaaa-2222-bbbb-3333cccc4444",
  "Domain": "contoso.onmicrosoft.com",
  "Instance": "https://login.microsoftonline.com/",
  "ResponseType": "code",
  "TenantId": "aaaabbbb-0000-cccc-1111-dddd2222eeee"
},

이 버전의 문서에서는 백엔드 포 프론트엔드(BFF) 패턴을 사용하여 엔트라 구현에 대해 설명합니다. 앱의 사양에서 BFF 패턴 채택을 요구하지 않는 경우 아티클 버전 선택기를 비 BFF 패턴 변경합니다.

다음 사양이 적용됩니다.

  • 전역 대화형 작업()과 함께 자동 렌더링 모드를 사용합니다.
  • 서버 프로젝트는 서버 측 인증 상태 공급자를 추가하기 위해 AddAuthenticationStateSerialization을(를) 호출하며, 이 공급자는 PersistentComponentState을 사용하여 인증 상태를 클라이언트로 전달합니다. 클라이언트는 서버에서 전달한 인증 상태를 역직렬화하고 사용하기 위해 호출 AddAuthenticationStateDeserialization 합니다. 인증 상태는 WebAssembly 애플리케이션의 수명 동안 고정됩니다.
  • 앱은 Microsoft 웹 패키지에 기반해 Identity를 사용합니다.
  • 자동 비대화형 토큰 새로 고침은 프레임워크에서 관리됩니다.
  • 앱은 서버 쪽 및 클라이언트 쪽 서비스 추상화로 생성된 날씨 데이터를 표시합니다.
  • BFF(프런트 엔드용 백 엔드) 패턴은 서비스 검색을 위해 .NET Aspire를 사용하고, YARP을 통해 백 엔드 앱의 일기 예보 엔드포인트로의 요청을 프록시하기 위해 채택됩니다.
    • 백 엔드 웹 API는 JWT 전달자 인증을 사용하여 로그인Blazor Web App에서 저장한 JWT 토큰의 cookie 유효성을 검사합니다.
    • Aspire는 .NET 클라우드 네이티브 앱을 빌드하는 환경을 개선합니다. 분산 앱을 빌드하고 실행하기 위한 일관되고 의견 있는 도구 및 패턴 집합을 제공합니다.
    • YARP(Yet Another Reverse Proxy)는 역방향 프록시 서버를 만드는 데 사용되는 라이브러리입니다.

자세한 .NET Aspire 정보는 .NET Aspire의 일반 공급: .NET 클라우드 네이티브 개발 간소화(2024년 5월)를 참조하세요.

필수 조건

.NET Aspire 에는 Visual Studio 버전 17.10 이상이 필요합니다.

또한 빠른 시작: 첫 번째 .NET Aspire 앱구축의 필수 구성 요소 섹션을 참조하세요.

샘플 앱

샘플 앱은 다음 5개의 프로젝트로 구성됩니다.

  • .NET Aspire:
    • Aspire.AppHost: 앱의 상위 수준 오케스트레이션 문제를 관리하는 데 사용됩니다.
    • Aspire.ServiceDefaults: 필요에 따라 확장 및 사용자 지정할 수 있는 기본 .NET Aspire 앱 구성을 포함합니다.
  • MinimalApiJwt: 날씨 데이터에 대한 최소 API 엔드포인트 예제 를 포함하는 백 엔드 웹 API 입니다.
  • BlazorWebAppEntra: Blazor Web App의 서버 측 프로젝트입니다.
  • BlazorWebAppEntra.Client: Blazor Web App 클라이언트 측 프로젝트입니다.

다음 링크를 사용하여 Blazor 샘플 리포지토리의 최신 버전 폴더를 통해 샘플에 액세스합니다. 샘플은 .NET 9 이상용 BlazorWebAppEntraBff 폴더에 있습니다.

샘플 코드 보기 및 다운로드(다운로드 방법)

.NET Aspire 프로젝트

샘플 앱의 .NET Aspire.AppHost 사용 .ServiceDefaults 및 프로젝트에 대한 자세한 내용은 설명서를 참조.NET Aspire하세요.

에 대한 .NET Aspire필수 구성 요소를 충족했는지 확인합니다. 자세한 내용은 빠른 시작: 첫 번째 앱.NET Aspire필수 구성 요소 섹션을 참조하세요.

샘플 앱은 개발 테스트 중에 사용할 안전하지 않은 HTTP 시작 프로필(http)만 구성합니다. 안전하지 않고 안전한 시작 설정 프로필의 예를 비롯한 자세한 내용은 (설명서)에서 .NET Aspire.NET Aspire 안전하지 않은 전송 허용을 참조하세요.

서버 쪽 Blazor Web App 프로젝트(BlazorWebAppEntra)

BlazorWebAppEntra 프로젝트는 Blazor Web App의 서버 쪽 프로젝트입니다.

클라이언트 쪽 Blazor Web App 프로젝트(BlazorWebAppEntra.Client)

BlazorWebAppEntra.Client 프로젝트는 Blazor Web App의 클라이언트 측 프로젝트입니다.

클라이언트 쪽 렌더링 중에 사용자가 로그인하거나 로그아웃해야 하는 경우 전체 페이지 다시 로드가 시작됩니다.

백 엔드 웹 API 프로젝트(MinimalApiJwt)

MinimalApiJwt 프로젝트는 여러 프런트 엔드 프로젝트에 대한 백 엔드 웹 API입니다. 이 프로젝트는 날씨 데이터에 대한 최소 API 엔드포인트를 구성합니다. 서버 측 프로젝트 Blazor Web App의 요청은 MinimalApiJwt 프로젝트로 BlazorWebAppOidc 프록시됩니다.

이 파일은 MinimalApiJwt.http 날씨 데이터 요청을 테스트하는 데 사용할 수 있습니다. 엔드포인트를 MinimalApiJwt 테스트하려면 프로젝트를 실행해야 하며 엔드포인트는 파일로 하드 코딩됩니다. 자세한 내용은 Visual Studio 2022에서 .http 파일 사용을 참조 하세요.

프로젝트의 Program 파일에서 안전한 일기 예보 데이터 엔드포인트:

app.MapGet("/weather-forecast", () =>
{
    var forecast = Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast
        (
            DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            Random.Shared.Next(-20, 55),
            summaries[Random.Shared.Next(summaries.Length)]
        ))
        .ToArray();
    return forecast;
}).RequireAuthorization();

확장 메서드에는 RequireAuthorization 경로 정의에 대한 권한 부여가 필요합니다. 프로젝트에 추가하는 모든 컨트롤러의 경우, 컨트롤러나 액션에 [Authorize] 특성을 추가합니다.

구성

이 섹션에서는 샘플 앱을 구성하는 방법을 설명합니다.

AddMicrosoftIdentityWebApp Microsoft Identity Web(Microsoft.Identity.WebNuGet 패키지, API 설명서)는 서버 프로젝트의 AzureAd 파일에 있는 appsettings.json 섹션에 의해 구성됩니다.

Entra 또는 Azure 포털의 앱 등록에서 리디렉션 URI가 있는 웹 플랫폼 구성을 사용하세요. 포트는 필요하지 않습니다. 암시적 권한 부여 및 하이브리드 흐름에서 ID 토큰 및 액세스 토큰이 선택되지 않은지 확인합니다. OpenID Connect 처리기는 권한 부여 엔드포인트에서 반환된 코드를 사용하여 적절한 토큰을 자동으로 요청합니다.

Weather.Get 범위는 Entra 또는 Azure 포털에서 API 를 노출하는에서 구성됩니다. 웹 API를 통해 날씨 데이터에 액세스하기 위해 API 권한을(를) 구성하지 마세요(위임된 권한 부여).

서버 프로젝트 구성

서버 프로젝트의 앱 설정 파일(appsettings.json)에서 앱의 AzureAd 섹션 구성을 제공합니다. Entra 또는 Azure Portal의 앱 등록에서 애플리케이션(클라이언트) ID, 테넌트(게시자) 도메인 및 디렉터리(테넌트) ID를 가져옵니다.

Weather.Get 범위에 대한 앱 ID URI를 가져옵니다. 범위 이름은 포함하지 말고, 끝에 슬래시를 사용하지 마세요.

"AzureAd": {
  "CallbackPath": "/signin-oidc",
  "ClientId": "{CLIENT ID}",
  "Domain": "{DOMAIN}",
  "Instance": "https://login.microsoftonline.com/",
  "ResponseType": "code",
  "TenantId": "{TENANT ID}",
  "AppIdUri": "{APP ID URI}"
},

이전 예제의 자리 표시자:

  • {CLIENT ID}: 애플리케이션(클라이언트) ID입니다.
  • {DOMAIN}: 테넌트(게시자) 도메인입니다.
  • {TENANT ID}: 디렉터리(테넌트) ID입니다.
  • {APP ID URI}: 애플리케이션 ID URI입니다.

예시:

"AzureAd": {
  "CallbackPath": "/signin-oidc",
  "ClientId": "00001111-aaaa-2222-bbbb-3333cccc4444",
  "Domain": "contoso.onmicrosoft.com",
  "Instance": "https://login.microsoftonline.com/",
  "ResponseType": "code",
  "TenantId": "aaaabbbb-0000-cccc-1111-dddd2222eeee",
  "AppIdUri": "api://00001111-aaaa-2222-bbbb-3333cccc4444"
},

콜백 경로(CallbackPath)는 Entra 또는 Azure Portal에서 애플리케이션을 등록할 때 구성된 리디렉션 URI(로그인 콜백 경로)와 일치해야 합니다. 경로는 앱 등록의 인증 블레이드에서 구성됩니다. 기본값 CallbackPath는 등록된 리디렉션 URI /signin-oidc에 대해 https://localhost/signin-oidc입니다. (포트는 필요하지 않음).

SignedOutCallbackPath(구성 키: "SignedOutCallbackPath")는 Entra에서 로그아웃한 후 사용자 에이전트가 처음 반환되는 곳으로, 앱의 기본 경로 내에서 OpenID Connect 처리기에 의해 가로채이는 요청 경로입니다. "/signout-callback-oidc"의 기본값이 사용되므로 샘플 앱은 경로에 대한 값을 설정하지 않습니다. 요청을 가로챈 후, OpenID Connect 처리기는 지정된 경우 SignedOutRedirectUri 또는 RedirectUri로 리디렉션됩니다.

앱의 Entra 등록에서 로그아웃 시 사용되는 콜백 경로를 구성합니다. Entra 또는 Azure Portal에서 Web 플랫폼 구성의 리디렉션 URI 항목에서 경로를 설정합니다.

https://localhost/signout-callback-oidc

참고

Entra를 사용하는 경우 localhost 주소에는 포트가 필요하지 않습니다.

Entra에서 앱 등록에 로그아웃된 콜백 경로 URI를 추가하지 않으면 Entra는 사용자를 앱으로 다시 리디렉션하는 것을 거부하고 브라우저 창을 닫도록 요청합니다.

참고

Entra는 기본 관리자 사용자(루트 계정) 또는 외부 사용자를 Blazor 애플리케이션으로 다시 리디렉션하지 않습니다. 대신 Entra는 사용자를 앱에서 로그아웃하고 모든 브라우저 창을 닫는 것이 좋습니다. 자세한 내용은 를 참조하세요. 기관 URL에 테넌트 ID가 포함된 경우 postLogoutRedirectUri가 작동하지 않습니다 (AzureAD/microsoft-authentication-library-for-js #5783).

경고

앱 비밀, 연결 문자열, 자격 증명, 암호, PIN(개인 식별 번호), 개인 C#/.NET 코드 또는 프라이빗 키/토큰을 항상 안전하지 않은 클라이언트 쪽 코드에 저장하지 마세요. 테스트/스테이징 및 프로덕션 환경에서 서버 쪽 Blazor 코드 및 웹 API는 프로젝트 코드 또는 구성 파일 내에서 자격 증명을 유지 관리하지 않는 보안 인증 흐름을 사용해야 합니다. 로컬 개발 테스트 외에는 환경 변수가 가장 안전한 방법이 아니므로 환경 변수를 사용하여 중요한 데이터를 저장하는 것을 피하는 것이 좋습니다. 로컬 개발 테스트의 경우 중요한 데이터를 보호하기 위해 Secret Manager 도구를 사용하는 것이 좋습니다. 자세한 내용은 중요한 데이터 및 자격 증명을 안전하게 유지 관리하세요.

백 엔드 웹 API 프로젝트 구성(MinimalApiJwt)

프로젝트의 Program 파일에 있는 AddJwtBearer 호출의 JwtBearerOptions에서 프로젝트를 구성합니다.

권위

Authority OIDC 호출을 위한 기관을 설정합니다.

jwtOptions.Authority = "{AUTHORITY}";

다음 예제에서는 aaaabbbb-0000-cccc-1111-dddd2222eeee테넌트 ID를 사용합니다.

앱이 ME-ID 테넌트에 등록된 경우 기관은 ID 공급자가 반환한 JWT의 발급자(iss)와 일치해야 합니다.

jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee/";

앱이 AAD B2C 테넌트에 등록된 경우:

jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/";

청중

Audience 수신된 OIDC 토큰에 대한 대상 그룹을 설정합니다.

jwtOptions.Audience = "{AUDIENCE}";

Entra 또는 Azure Portal에서 API 노출 아래에 Weather.Get 범위를 추가할 때 구성된 애플리케이션 ID URI 경로에만 값을 일치합니다.

다음 예제에서는 00001111-aaaa-2222-bbbb-3333cccc4444애플리케이션(클라이언트) ID({CLIENT ID})를 사용합니다. 두 번째 예제에서는 contoso디렉터리 이름({DIRECTORY NAME})을 사용합니다.

앱이 ME-ID 테넌트에 등록된 경우:

앱 ID URI({APP ID URI}): api://{CLIENT ID}

jwtOptions.Audience = "api://00001111-aaaa-2222-bbbb-3333cccc4444";

앱이 AAD B2C 테넌트에 등록된 경우:

앱 ID URI({APP ID URI}): https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID}

jwtOptions.Audience = "https://contoso.onmicrosoft.com/00001111-aaaa-2222-bbbb-3333cccc4444";

클라이언트 암호 설정

Entra 또는 Azure Portal에서 앱의 Entra ID 등록에 클라이언트 비밀을 만듭니다(인증서 및 비밀 새 클라이언트 암호> 관리>). 다음 지침에서 새 비밀의 값을 사용합니다.

다음 방법 중 하나 또는 둘 다를 사용하여 앱에 클라이언트 비밀을 제공합니다.

  • 비밀 관리자 도구: Secret Manager 도구는 로컬 컴퓨터에 개인 데이터를 저장하며 로컬 개발 중에만 사용됩니다.
  • Azure Key Vault: 로컬로 작업할 때 개발 환경을 비롯한 모든 환경에서 사용할 수 있는 키 자격 증명 모음에 클라이언트 비밀을 저장할 수 있습니다. 일부 개발자는 스테이징 및 프로덕션 배포에 키 자격 증명 모음을 사용하고 로컬 개발에는 Secret Manager 도구를 사용하는 것을 선호합니다.

프로젝트 코드 또는 구성 파일에 클라이언트 비밀을 저장하지 않는 것이 좋습니다. 이 섹션의 방법 중 하나 또는 둘 다와 같은 보안 인증 흐름을 사용합니다.

비밀 관리자 도구

Secret Manager 도구구성 키 AzureAd:ClientSecret아래에 서버 앱의 클라이언트 비밀을 저장할 수 있습니다.

샘플 앱Secret Manager 도구에 대해 초기화되지 않았습니다. Visual Studio의 Developer PowerShell 명령 셸과 같은 명령 셸을 사용하여 다음 명령을 실행합니다. 명령을 실행하기 전에 명령을 사용하여 디렉터리를 cd 서버 프로젝트의 디렉터리로 변경합니다. 이 명령은 서버 앱의 프로젝트 파일에 사용자 비밀 식별자(<UserSecretsId>)를 설정합니다. 이 식별자는 도구에서 앱의 비밀을 추적하는 데 내부적으로 사용됩니다.

dotnet user-secrets init

다음 명령을 실행하여 클라이언트 암호를 설정합니다. {SECRET} 자리 표시자는 앱의 Entra 등록에서 가져온 클라이언트 암호입니다.

dotnet user-secrets set "AzureAd:ClientSecret" "{SECRET}"

Visual Studio를 사용하는 경우 솔루션 탐색기 서버 프로젝트를 마우스 오른쪽 단추로 클릭하고 사용자 비밀 관리를 선택하여 비밀이 설정되었는지 확인할 수 있습니다.

Azure Key Vault

Azure Key Vault 는 앱에 앱의 클라이언트 비밀을 제공하기 위한 안전한 방법을 제공합니다.

키 자격 증명 모음을 만들고 클라이언트 비밀을 설정하려면 Azure Key Vault를 시작하기 위해 리소스를 상호 연결하는 Azure Key Vault 비밀 정보(Azure 설명서)를 참조하세요. 이 섹션의 코드를 구현하려면, 키 자격 증명 모음과 비밀을 만들 때 Azure에서 키 자격 증명 모음 URI와 비밀 이름을 기록해 두십시오. 액세스 정책 패널에서 비밀에 대한 액세스 정책을 설정하는 경우:

  • 비밀 가져오기 권한만 필요합니다.
  • 애플리케이션을 비밀에 대한 보안 주체로 선택합니다.

중요함

키 자격 증명 보관소 비밀은 만료 날짜와 함께 생성됩니다. 키 자격 증명 모음의 비밀이 만료되는 시기를 반드시 추적하고 해당 날짜가 지나기 전에 앱용 새 비밀을 만들어야 합니다.

서버 프로젝트에 다음 AzureHelper 클래스를 추가합니다. GetKeyVaultSecret 메서드는 키 자산 저장소에서 비밀을 검색합니다. 프로젝트 네임스페이스 체계와 일치하도록 네임스페이스(BlazorSample.Helpers)를 조정합니다.

Helpers/AzureHelper.cs:

using Azure;
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;

namespace BlazorSample.Helpers;

public static class AzureHelper
{
    public static string GetKeyVaultSecret(string tenantId, string vaultUri, string secretName)
    {
        DefaultAzureCredentialOptions options = new()
        {
            // Specify the tenant ID to use the dev credentials when running the app locally
            // in Visual Studio.
            VisualStudioTenantId = tenantId,
            SharedTokenCacheTenantId = tenantId
        };

        var client = new SecretClient(new Uri(vaultUri), new DefaultAzureCredential(options));
        var secret = client.GetSecretAsync(secretName).Result;

        return secret.Value.Value;
    }
}

서버 프로젝트의 Program 파일에 서비스가 등록된 경우 다음 코드를 사용하여 클라이언트 암호를 가져오고 적용합니다.

var tenantId = builder.Configuration.GetValue<string>("AzureAd:TenantId")!;
var vaultUri = builder.Configuration.GetValue<string>("AzureAd:VaultUri")!;
var secretName = builder.Configuration.GetValue<string>("AzureAd:SecretName")!;

builder.Services.Configure<MicrosoftIdentityOptions>(
    OpenIdConnectDefaults.AuthenticationScheme,
    options =>
    {
        options.ClientSecret = 
            AzureHelper.GetKeyVaultSecret(tenantId, vaultUri, secretName);
    });

예를 들어 로컬 개발에 Secret Manager 도구를 사용하도록 선택했기 때문에 코드를 로컬로 실행하지 않도록 하기 위해 이전 코드가 작동하는 환경을 제어하려는 경우 환경을 확인하는 조건문에서 이전 코드를 래핑할 수 있습니다.

if (!context.HostingEnvironment.IsDevelopment())
{
    ...
}

AzureAd appsettings.json 섹션에 다음의 VaultUriSecretName 구성 키와 값을 추가합니다.

"VaultUri": "{VAULT URI}",
"SecretName": "{SECRET NAME}"

앞의 예에서:

  • {VAULT URI} 자리 표시자는 키 볼트 URI입니다. URI에 후행 슬래시를 포함합니다.
  • {SECRET NAME} 자리 표시자는 비밀 이름입니다.

예시:

"VaultUri": "https://contoso.vault.azure.net/",
"SecretName": "BlazorWebAppEntra"

구성은 앱의 환경 구성 파일을 기반으로 키 보관소와 시크릿 이름을 쉽게 제공하는 데 사용됩니다. 예를 들어, 개발 시 appsettings.Development.json에, 준비 시 appsettings.Staging.json에, 프로덕션 배포 시 appsettings.Production.json에 서로 다른 구성 값을 제공할 수 있습니다. 자세한 내용은 ASP.NET Core Blazor 구성을 참조하세요.

로그아웃할 때 홈페이지로 리디렉션

LogInOrOut 구성 요소(Layout/LogInOrOut.razor)는 반환 URL(ReturnUrl)의 숨겨진 필드를 현재 URL(currentURL)로 설정합니다. 사용자가 앱에서 로그아웃하면 ID 공급자가 로그아웃한 페이지로 사용자를 반환합니다. 사용자가 보안 페이지에서 로그아웃하는 경우 동일한 보안 페이지로 반환되고 인증 프로세스를 통해 다시 전송됩니다. 이 인증 흐름은 사용자가 정기적으로 계정을 변경해야 하는 경우에 합리적입니다.

다른 방법으로, 로그아웃 시 리턴 URL을 제공하지 않는 다음 LogInOrOut 구성 요소를 사용할 수 있습니다.

Layout/LogInOrOut.razor:

<div class="nav-item px-3">
    <AuthorizeView>
        <Authorized>
            <form action="authentication/logout" method="post">
                <AntiforgeryToken />
                <button type="submit" class="nav-link">
                    <span class="bi bi-arrow-bar-left-nav-menu" aria-hidden="true">
                    </span> Logout
                </button>
            </form>
        </Authorized>
        <NotAuthorized>
            <a class="nav-link" href="authentication/login">
                <span class="bi bi-person-badge-nav-menu" aria-hidden="true"></span>
                Login
            </a>
        </NotAuthorized>
    </AuthorizeView>
</div>

날씨 데이터 보안

이 앱이 날씨 데이터를 어떻게 보호하는지에 대한 자세한 내용은 대화형 자동 렌더링 를 사용하여 Blazor Web App에서보안 데이터를 참조하십시오.

문제 해결

로깅

서버 앱은 표준 ASP.NET Core 앱입니다. 서버 앱에서 낮은 로깅 수준을 사용하도록 설정하려면 ASP.NET Core 로깅 지침을 참조하세요.

인증 Blazor WebAssembly 디버그 또는 추적 로깅을 사용하려면, 문서 버전 선택기가 ASP.NET Core 7.0 이상으로 설정된 Blazor의 클라이언트 측 인증 로깅 섹션을 참조하세요.

일반 오류

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

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

    • 시나리오의 요구 사항에 따라, 누락되거나 잘못된 권한, 인스턴스, 테넌트 ID, 테넌트 도메인, 클라이언트 ID 또는 리디렉션 URI 때문에 앱에서 클라이언트를 인증하지 못합니다.
    • 잘못된 요청 범위는 클라이언트가 서버 웹 API 엔드포인트에 액세스하지 못하게 합니다.
    • 서버 API 권한이 잘못되거나 누락되어 클라이언트가 서버 웹 API 엔드포인트에 액세스할 수 없습니다.
    • IP 앱 등록의 리디렉션 URI에 구성된 것과 다른 포트에서 앱을 실행합니다. Microsoft Entra ID와 개발 테스트 주소에서 localhost 실행되는 앱에는 포트가 필요하지 않지만, 주소 localhost가 아닌 경우, 앱의 포트 구성과 실제 실행 중인 포트가 일치해야 합니다.

    이 문서의 구성 범위는 올바른 구성의 예를 보여줍니다. 앱 및 IP의 잘못된 구성을 신중하게 확인하세요.

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

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

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

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

    이전 포럼은 Microsoft에서 소유하거나 제어하지 않습니다.

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

  • ME-ID에 대한 권한 없는 클라이언트

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

    ME-ID의 로그인 콜백 오류:

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

    오류를 해결하려면:

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

쿠키 및 사이트 데이터

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

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

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

  • 브라우저 구성
    • 브라우저가 닫힐 때마다 모든 cookie 및 사이트 데이터를 삭제하도록 구성할 수 있는 브라우저를 사용하세요.
    • 앱, 테스트 사용자 또는 공급자 구성을 변경할 때 수동으로 또는 IDE를 통해 브라우저를 닫습니다.
  • 사용자 지정 명령을 사용하여 Visual Studio에서 InPrivate 또는 Incognito 모드로 브라우저를 엽니다.
    • 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
    • 인수 필드에서 브라우저가 InPrivate 또는 Incognito 모드에서 여는 데 사용하는 명령줄 옵션을 제공합니다. 일부 브라우저에는 앱의 URL이 필요합니다.
      • Microsoft Edge: 을 사용하십시오.
      • Google Chrome: --incognito --new-window {URL} 자리 표시자에 열 URL을 입력하여 {URL}(예: https://localhost:5001)를 사용합니다.
      • Mozilla Firefox: -private -url {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 갤러리사용합니다.

서버 앱 실행

테스트 및 문제 해결 시 Blazor Web App서버 프로젝트에서 앱을 실행하고 있는지 확인합니다.

사용자 확인

다음 UserClaims 구성 요소는 앱에서 직접 사용하거나 추가 사용자 지정의 기준으로 사용할 수 있습니다.

UserClaims.razor:

@page "/user-claims"
@using System.Security.Claims
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]

<PageTitle>User Claims</PageTitle>

<h1>User Claims</h1>

@if (claims.Any())
{
    <ul>
        @foreach (var claim in claims)
        {
            <li><b>@claim.Type:</b> @claim.Value</li>
        }
    </ul>
}

@code {
    private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();

    [CascadingParameter]
    private Task<AuthenticationState>? AuthState { get; set; }

    protected override async Task OnInitializedAsync()
    {
        if (AuthState == null)
        {
            return;
        }

        var authState = await AuthState;
        claims = authState.User.Claims;
    }
}

추가 리소스