MICROSOFT Entra(ME-ID) 그룹, 관리주부 역할 및 앱 역할

참고 항목

이 문서의 최신 버전은 아닙니다. 현재 릴리스는 이 문서의 .NET 8 버전을 참조 하세요.

Important

이 정보는 상업적으로 출시되기 전에 실질적으로 수정될 수 있는 시험판 제품과 관련이 있습니다. Microsoft는 여기에 제공된 정보에 대해 어떠한 명시적, 또는 묵시적인 보증을 하지 않습니다.

현재 릴리스는 이 문서의 .NET 8 버전을 참조 하세요.

이 문서에서는 Microsoft Entra ID 그룹 및 역할을 사용하도록 구성하는 Blazor WebAssembly 방법을 설명합니다.

MICROSOFT Entra(ME-ID)는 ASP.NET Core Identity와 결합할 수 있는 몇 가지 권한 부여 방법을 제공합니다.

  • Groups
    • 보안
    • Microsoft 365
    • 배포
  • 역할
    • ME-ID 관리주부 역할
    • 앱 역할

이 문서의 지침은 다음 항목에 Blazor WebAssembly 설명된 ME-ID 배포 시나리오에 적용됩니다.

이 문서에서는 클라이언트 앱과 서버 앱에 대한 지침을 제공합니다.

  • 클라이언트: 독립 실행형 Blazor WebAssembly 앱.
  • 서버: ASP.NET Core 서버 API/웹 API 앱. 독립 실행형 Blazor WebAssembly 앱에 대한 문서 전체에서 SERVER 지침을 무시할 수 있습니다.
  • CLIENT: 독립 실행형 Blazor WebAssembly 앱 또는 호스트된 Blazor솔루션Client 앱입니다.
  • SERVER: ASP.NET Core 서버 API/웹 API 앱 또는 호스트된 Blazor 솔루션의 Server 앱. 독립 실행형 Blazor WebAssembly 앱에 대한 문서 전체에서 SERVER 지침을 무시할 수 있습니다.

이 문서의 예제에서는 새로운 .NET/C# 기능을 활용합니다. .NET 7 이전 버전에서 예제를 사용하는 경우 약간의 수정이 필요합니다. 그러나 ME-ID 및 Microsoft Graph와 상호 작용하는 것과 관련된 텍스트 및 코드 예제는 모든 버전의 ASP.NET Core에서 동일합니다.

전제 조건

이 문서의 지침은 ASP.NET Core Blazor WebAssembly로 Graph API 사용의 .Graph SDK 지침에 따라 Microsoft Graph API를 구현합니다. Graph SDK 구현 지침에 따라 앱을 구성하고 테스트하여 앱이 테스트 사용자 계정에 대한 Graph API 데이터를 가져올 수 있음을 확인합니다. 또한, Microsoft Graph 보안 개념을 검토하려면 Graph API 문서의 보안 문서 교차 링크를 참조하세요.

Graph SDK를 로컬로 테스트할 때, 느린 cookie가 테스트를 방해하지 않도록 각 테스트에 대해 새 프라이빗/시크릿 브라우저 세션을 사용하는 것이 좋습니다. 자세한 내용은 Microsoft Entra ID를 사용하여 ASP.NET Core Blazor WebAssembly 독립 실행형 앱 보안을 참조하세요.

범위

Microsoft Graph API에 사용자 프로필, 역할 할당 및 그룹 멤버 자격 데이터에 대한 호출을 허용하려면 다음을 수행합니다.

  • 클라이언트 앱은 Azure Portal에서 위임된User.Read 범위(https://graph.microsoft.com/User.Read)로 구성됩니다. 사용자 데이터를 읽는 액세스 권한은 개별 사용자에게 부여(위임된) 범위에 따라 결정되기 때문입니다.
  • 서버 앱은 Azure Portal의 애플리케이션GroupMember.Read.All 범위(https://graph.microsoft.com/GroupMember.Read.All)로 구성됩니다. 액세스는 앱이 그룹 구성원에 대한 데이터에 액세스하기 위한 개별 사용자 권한 부여를 기반으로 하지 않고 그룹 멤버 자격에 대한 정보를 가져오는 데 사용되므로 구성됩니다.

앞의 범위는 앞서 나열된 항목(Microsoft 계정으로 독립 실행형 또는 ME-ID가 있는 독립 실행형)에서 설명한 ME ID 배포 시나리오에 필요한 범위 외에 필요합니다.

앞의 범위는 앞서 나열된 항목(Microsoft 계정으로 독립 실행형, ME-ID가 있는 독립 실행형 및 ME-ID로 호스트됨)에서 설명한 ME-ID 배포 시나리오에 필요한 범위 외에 필요합니다.

자세한 내용은 microsoft Graph 권한의 Microsoft ID 플랫폼 및 개요에서 사용 권한 및 동의 개요를 참조하세요.

참고 항목

"사용 권한" 단어와 "범위" 단어는 Azure Portal과 다양한 Microsoft 및 외부 설명서에서 서로 바꿔 사용됩니다. 이 문서에서는 Azure Portal에서 앱에 할당된 사용 권한에 "범위"라는 단어를 계속 사용합니다.

그룹 멤버 자격 클레임 특성

Azure Portal에서 CLIENTSERVER 앱의 앱 매니페스트에서 groupMembershipClaims 특성All로 설정합니다. ME-ID가 All 잘 알려진 ID 클레임(wids)에서 로그인한 사용자의 모든 보안 그룹, 메일 그룹 및 역할을 보내는 결과 값입니다.

  1. 앱의 Azure Portal 등록을 엽니다.
  2. 사이드바에서 관리>매니페스트를 선택합니다.
  3. groupMembershipClaims 특성을 찾습니다.
  4. 값을 All("groupMembershipClaims": "All")로 설정합니다.
  5. 변경한 경우 저장 단추를 선택합니다.

사용자 지정 사용자 계정

Azure Portal에서 ME-ID 보안 그룹 및 ME-ID 관리주부 역할에 사용자를 할당합니다.

이 문서의 예제는 다음과 같습니다.

  • 서버 API 데이터에 액세스하기 위한 권한 부여를 위해 사용자가 Azure Portal ME-ID 테넌트의 ME-ID 청구 관리 주 서버 역할에 할당된다고 가정합니다.
  • 권한 부여 정책을 사용하여 CLIENTSERVER 앱 내의 액세스를 제어합니다.

CLIENT 앱에서 RemoteUserAccount를 확장하여 다음 속성을 포함합니다.

CustomUserAccount.cs:

using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

namespace BlazorSample;

public class CustomUserAccount : RemoteUserAccount
{
    [JsonPropertyName("roles")]
    public List<string>? Roles { get; set; }

    [JsonPropertyName("wids")]
    public List<string>? Wids { get; set; }

    [JsonPropertyName("oid")]
    public string? Oid { get; set; }
}

Microsoft.GraphCLIENT 앱에 패키지 참조를 추가합니다.

참고 항목

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

ASP.NET Core Blazor WebAssembly에서 Graph API 사용 문서의 Graph SDK 지침에서 Graph SDK 유틸리티 클래스 및 구성을 추가합니다. 문서의 예제 wwwroot/appsettings.json 파일에 표시된 대로 액세스 토큰의 User.Read 범위를 지정합니다.

CLIENT 앱에 다음 사용자 지정 사용자 계정 팩터리를 추가합니다. 사용자 지정 사용자 팩터리는 다음을 설정하는 데 사용됩니다.

  • 앱 역할 클레임(appRole)(앱 역할 섹션에서 설명).
  • ME-ID 관리istrator 역할 클레임(directoryRole).
  • 사용자의 휴대폰 번호(mobilePhone) 및 사무실 위치(officeLocation)에 대한 사용자 프로필 데이터 클레임 예제.
  • ME-ID 그룹 클레임(directoryGroup).
  • 정보 또는 오류를 기록하려는 경우 편의를 위한 ILogger(logger).

CustomAccountFactory.cs:

다음 예제에서는 프로젝트의 앱 설정 파일에 기본 URL에 대한 항목이 포함되어 있다고 가정합니다.

{
  "MicrosoftGraph": {
    "BaseUrl": "https://graph.microsoft.com/{VERSION}",
    ...
  }
}

앞의 예제 {VERSION} 에서 자리 표시자는 MS Graph API의 버전입니다(예: v1.0).

using System.Security.Claims;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;
using Microsoft.Graph;
using Microsoft.Kiota.Abstractions.Authentication;

namespace BlazorSample;

public class CustomAccountFactory(IAccessTokenProviderAccessor accessor,
        IServiceProvider serviceProvider,
        ILogger<CustomAccountFactory> logger,
        IConfiguration config)
    : AccountClaimsPrincipalFactory<CustomUserAccount>(accessor)
{
    private readonly ILogger<CustomAccountFactory> logger = logger;
    private readonly IServiceProvider serviceProvider = serviceProvider;
    private readonly string? baseUrl = 
        config.GetSection("MicrosoftGraph")["BaseUrl"];

    public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
        CustomUserAccount account,
        RemoteAuthenticationUserOptions options)
    {
        var initialUser = await base.CreateUserAsync(account, options);

        if (initialUser.Identity is not null &&
            initialUser.Identity.IsAuthenticated)
        {
            var userIdentity = initialUser.Identity as ClaimsIdentity;

            if (userIdentity is not null && !string.IsNullOrEmpty(baseUrl))
            {
                account?.Roles?.ForEach((role) =>
                {
                    userIdentity.AddClaim(new Claim("appRole", role));
                });

                account?.Wids?.ForEach((wid) =>
                {
                    userIdentity.AddClaim(new Claim("directoryRole", wid));
                });

                try
                {
                    var client = new GraphServiceClient(
                        new HttpClient(),
                        serviceProvider
                            .GetRequiredService<IAuthenticationProvider>(),
                        baseUrl);

                    var user = await client.Me.GetAsync();

                    if (user is not null)
                    {
                        userIdentity.AddClaim(new Claim("mobilephone",
                            user.MobilePhone ?? "(000) 000-0000"));
                        userIdentity.AddClaim(new Claim("officelocation",
                            user.OfficeLocation ?? "Not set"));
                    }

                    var requestMemberOf = client.Users[account?.Oid].MemberOf;
                    var memberships = await requestMemberOf.Request().GetAsync();

                    if (memberships is not null)
                    {
                        foreach (var entry in memberships)
                        {
                            if (entry.ODataType == "#microsoft.graph.group")
                            {
                                userIdentity.AddClaim(
                                    new Claim("directoryGroup", entry.Id));
                            }
                        }
                    }
                }
                catch (AccessTokenNotAvailableException exception)
                {
                    exception.Redirect();
                }
            }
        }

        return initialUser;
    }
}
using System.Security.Claims;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;
using Microsoft.Graph;

namespace BlazorSample;

public class CustomAccountFactory(IAccessTokenProviderAccessor accessor,
        IServiceProvider serviceProvider,
        ILogger<CustomAccountFactory> logger)
    : AccountClaimsPrincipalFactory<CustomUserAccount>(accessor)
{
    private readonly ILogger<CustomAccountFactory> logger = logger;
    private readonly IServiceProvider serviceProvider = serviceProvider;

    public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
        CustomUserAccount account,
        RemoteAuthenticationUserOptions options)
    {
        var initialUser = await base.CreateUserAsync(account, options);

        if (initialUser.Identity is not null &&
            initialUser.Identity.IsAuthenticated)
        {
            var userIdentity = initialUser.Identity as ClaimsIdentity;

            if (userIdentity is not null)
            {
                account?.Roles?.ForEach((role) =>
                {
                    userIdentity.AddClaim(new Claim("appRole", role));
                });

                account?.Wids?.ForEach((wid) =>
                {
                    userIdentity.AddClaim(new Claim("directoryRole", wid));
                });

                try
                {
                    var client = ActivatorUtilities
                        .CreateInstance<GraphServiceClient>(serviceProvider);
                    var request = client.Me.Request();
                    var user = await request.GetAsync();

                    if (user is not null)
                    {
                        userIdentity.AddClaim(new Claim("mobilephone",
                            user.MobilePhone ?? "(000) 000-0000"));
                        userIdentity.AddClaim(new Claim("officelocation",
                            user.OfficeLocation ?? "Not set"));
                    }

                    var requestMemberOf = client.Users[account?.Oid].MemberOf;
                    var memberships = await requestMemberOf.Request().GetAsync();

                    if (memberships is not null)
                    {
                        foreach (var entry in memberships)
                        {
                            if (entry.ODataType == "#microsoft.graph.group")
                            {
                                userIdentity.AddClaim(
                                    new Claim("directoryGroup", entry.Id));
                            }
                        }
                    }
                }
                catch (AccessTokenNotAvailableException exception)
                {
                    exception.Redirect();
                }
            }
        }

        return initialUser;
    }
}

위의 코드에는 전이적 멤버 자격이 포함되어 있지 않습니다. 앱에 직접 및 전이적 그룹 멤버 자격 클레임이 필요한 경우 MemberOf 속성(IUserMemberOfCollectionWithReferencesRequestBuilder)을 TransitiveMemberOf(IUserTransitiveMemberOfCollectionWithReferencesRequestBuilder)로 바꿉니다.

앞의 코드는 ME-ID 관리이스트레이터 역할(형식)인 그룹 멤버 자격 클레임groups()을 무시합니다. Microsoft ID 플랫폼 반환된 GUID 값은 역할 템플릿 ID가 아닌 ME ID 관리주체 역할 엔터티 ID이기 때문#microsoft.graph.directoryRole입니다. 엔터티 ID는 Microsoft ID 플랫폼의 테넌트에서 안정적이지 않으며 앱에서 사용자에 대한 권한 부여 정책을 만드는 데 사용할 수 없습니다. 클레임에서 제공하는 ME-ID 관리주제 역할에는 항상 역할 템플릿 IDwids 사용합니다.

CLIENT 앱에서 사용자 지정 사용자 계정 팩터리를 사용하도록 MSAL 인증을 구성합니다.

Program 파일이 Microsoft.AspNetCore.Components.WebAssembly.Authentication 네임스페이스를 사용하는지 확인합니다.

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

AddMsalAuthentication 호출을 다음으로 업데이트합니다. Blazor 프레임워크의 RemoteUserAccount는 MSAL 인증 및 계정 클레임 보안 주체 팩터리에 대한 앱의 CustomUserAccount으로 대체됩니다.

builder.Services.AddMsalAuthentication<RemoteAuthenticationState,
    CustomUserAccount>(options =>
    {
        builder.Configuration.Bind("AzureAd",
            options.ProviderOptions.Authentication);
    })
    .AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, CustomUserAccount,
        CustomAccountFactory>();

ASP.NET Core Blazor WebAssembly로 Graph API 사용 문서에 설명된 Graph SDK 코드가 있는지 확인하고 Graph SDK 지침에 따라 wwwroot/appsettings.json 구성이 올바른지 확인합니다.

var baseUrl = string.Join("/", 
    builder.Configuration.GetSection("MicrosoftGraph")["BaseUrl"], 
    builder.Configuration.GetSection("MicrosoftGraph")["Version"]);
var scopes = builder.Configuration.GetSection("MicrosoftGraph:Scopes")
    .Get<List<string>>();

builder.Services.AddGraphClient(baseUrl, scopes);

wwwroot/appsettings.json:

{
  "MicrosoftGraph": {
    "BaseUrl": "https://graph.microsoft.com",
    "Version: "v1.0",
    "Scopes": [
      "user.read"
    ]
  }
}

권한 부여 구성

클라이언트 앱에서 파일의 앱 역할, ME-ID 관리istrator 역할 또는 보안 그룹에 Program 대한 정책을 만듭니다. 다음 예제에서는 ME-ID 청구 관리istrator 역할에 대한 정책을 만듭니다.

builder.Services.AddAuthorizationCore(options =>
{
    options.AddPolicy("BillingAdministrator", policy => 
        policy.RequireClaim("directoryRole", 
            "b0f54661-2d74-4c50-afa3-1ec803f12efe"));
});

ME-ID 관리istrator Role에 대한 ID의 전체 목록은 Entra 설명서의 역할 템플릿 ID를 참조하세요. 권한 부여 정책에 대한 자세한 내용은 ASP.NET Core의 정책 기반 권한 부여를 참조하세요.

다음 예제에서 CLIENT 앱은 앞의 정책을 사용하여 사용자에게 권한을 부여합니다.

AuthorizeView 구성 요소는 이 정책을 준수합니다.

<AuthorizeView Policy="BillingAdministrator">
    <Authorized>
        <p>
            The user is in the 'Billing Administrator' ME-ID Administrator Role
            and can see this content.
        </p>
    </Authorized>
    <NotAuthorized>
        <p>
            The user is NOT in the 'Billing Administrator' role and sees this
            content.
        </p>
    </NotAuthorized>
</AuthorizeView>

전체 구성 요소에 대한 액세스는 [Authorize] 특성 지시문(AuthorizeAttribute)을 사용하는 정책을 기반으로 할 수 있습니다.

@page "/"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Policy = "BillingAdministrator")]

사용자에게 권한이 없는 경우 ME-ID 로그인 페이지로 리디렉션됩니다.

절차 논리를 사용하여 코드에서 정책 검사를 수행할 수도 있습니다.

CheckPolicy.razor:

@page "/checkpolicy"
@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService AuthorizationService

<h1>Check Policy</h1>

<p>This component checks a policy in code.</p>

<button @onclick="CheckPolicy">Check 'BillingAdministrator' policy</button>

<p>Policy Message: @policyMessage</p>

@code {
    private string policyMessage = "Check hasn't been made yet.";

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

    private async Task CheckPolicy()
    {
        var user = (await authenticationStateTask).User;

        if ((await AuthorizationService.AuthorizeAsync(user, 
            "BillingAdministrator")).Succeeded)
        {
            policyMessage = "Yes! The 'BillingAdministrator' policy is met.";
        }
        else
        {
            policyMessage = "No! 'BillingAdministrator' policy is NOT met.";
        }
    }
}

서버 API/웹 API 액세스 권한 부여

서버 API 앱은 액세스 토큰widsgroups에 포함되는 경우 보안 그룹, ME-ID 관리이스트레이터 역할 및 앱 역할에 대한 권한 부여 정책을 사용하여 보안 API 엔드포인트에 액세스하도록 사용자에게 권한을 부여할 수 있습니다role. 다음 예제에서는 (잘 알려진 ID/역할 템플릿 ID) 클레임을 사용하여 wids 파일에 ME-ID 청구 관리주체 역할에 Program 대한 정책을 만듭니다.

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("BillingAdministrator", policy => 
        policy.RequireClaim("wids", "b0f54661-2d74-4c50-afa3-1ec803f12efe"));
});

ME-ID 관리istrator 역할에 대한 ID의 전체 목록은 Azure 설명서의 역할 템플릿 ID를 참조하세요. 권한 부여 정책에 대한 자세한 내용은 ASP.NET Core의 정책 기반 권한 부여를 참조하세요.

SERVER 앱의 컨트롤러에 대한 액세스는 정책 이름과 함께 [Authorize] 특성 사용을 기반으로 할 수 있습니다(API 설명서: AuthorizeAttribute).

다음 예제는 정책 이름 BillingAdministrator를 사용하여 BillingDataController의 청구 데이터에 대한 액세스를 Azure 대금 청구 관리자로 제한합니다.

using Microsoft.AspNetCore.Authorization;
[Authorize(Policy = "BillingAdministrator")]
[ApiController]
[Route("[controller]")]
public class BillingDataController : ControllerBase
{
    ...
}

자세한 내용은 ASP.NET Core의 정책 기반 권한 부여를 참조하세요.

앱 역할

앱 역할 멤버 자격 클레임을 제공하도록 Azure Portal에서 앱을 구성하려면 애플리케이션에 앱 역할 추가를 참조 하고 Entra 설명서의 토큰 에서 해당 역할을 받습니다.

다음 예제에서는 CLIENTSERVER 앱이 두 개의 역할로 구성되고 이 역할이 테스트 사용자에게 할당된다고 가정합니다.

  • Admin
  • Developer

참고 항목

독립 실행형 앱의 클라이언트-서버 쌍(독립 실행형 Blazor WebAssembly 앱 및 ASP.NET Core 서버 API/웹 API 앱) appRoles 을 개발할 때 클라이언트 및 서버 Azure Portal 앱 등록의 매니페스트 속성에는 동일한 구성된 역할이 포함되어야 합니다. 클라이언트 앱의 매니페스트에 역할을 설정한 후 역할 전체를 서버 앱의 매니페스트에 복사합니다. 클라이언트 앱 등록과 서버 앱 등록 간에 매니페스트 appRoles를 미러링하지 않는 경우 액세스 토큰 role클레임에 올바른 엔트리가 있는 경우에도 서버 API/웹 API의 인증된 사용자에 대해 역할 클레임이 설정되지 않습니다.

참고 항목

호스트된 Blazor WebAssembly 앱 또는 독립 실행형 앱의 클라이언트-서버 쌍(독립 실행형 Blazor WebAssembly 앱 및 ASP.NET Core 서버 API/웹 API 앱)을 개발하는 경우 클라이언트 및 서버 Azure Portal 앱 등록 appRoles 매니페스트 속성은 구성된 동일한 역할을 포함해야 합니다. 클라이언트 앱의 매니페스트에 역할을 설정한 후 역할 전체를 서버 앱의 매니페스트에 복사합니다. 클라이언트 앱 등록과 서버 앱 등록 간에 매니페스트 appRoles를 미러링하지 않는 경우 액세스 토큰 role클레임에 올바른 엔트리가 있는 경우에도 서버 API/웹 API의 인증된 사용자에 대해 역할 클레임이 설정되지 않습니다.

Microsoft Entra ID Premium 계정이 없는 그룹에 역할을 할당할 수는 없지만 사용자에게 역할을 할당하고 표준 Azure 계정을 사용하는 사용자에 대한 클레임을 받을 role 수 있습니다. 이 섹션의 지침에는 ME-ID Premium 계정이 필요하지 않습니다.

프리미엄 계층 Azure 계정이 있는 경우, 관리>앱 역할이 Azure Portal 앱 등록 사이드바에 표시됩니다. 애플리케이션에 앱 역할 추가의 지침에 따라 토큰 에서 해당 역할을 수신하여 앱의 역할을 구성합니다.

프리미엄 계층 Azure 계정이 없는 경우, Azure Portal 앱의 매니페스트를 편집합니다. 애플리케이션 역할: 구현의 지침에 따라 매니페스트 파일의 항목에서 appRoles 수동으로 앱의 역할을 설정합니다. 변경 내용을 파일에 저장합니다.

다음은 AdminDeveloper 역할을 만드는 예제 appRoles 항목입니다. 이러한 예제 역할은 구성 요소 수준에서 이 섹션의 예제 뒷부분에서 액세스 제한을 구현하는 데 사용됩니다.

"appRoles": [
  {
    "allowedMemberTypes": [
      "User"
    ],
    "description": "Administrators manage developers.",
    "displayName": "Admin",
    "id": "584e483a-7101-404b-9bb1-83bf9463e335",
    "isEnabled": true,
    "lang": null,
    "origin": "Application",
    "value": "Admin"
  },
  {
    "allowedMemberTypes": [
      "User"
    ],
    "description": "Developers write code.",
    "displayName": "Developer",
    "id": "82770d35-2a93-4182-b3f5-3d7bfe9dfe46",
    "isEnabled": true,
    "lang": null,
    "origin": "Application",
    "value": "Developer"
  }
],

사용자(또는 프리미엄 계층 Azure 계정이 있는 경우, 그룹)에 역할을 할당하려면 다음을 수행합니다.

  1. Azure Portal의 ME-ID 영역에서 엔터프라이즈 애플리케이션으로 이동합니다.
  2. app을 선택합니다. 사이드바에서관리>사용자 및 그룹을 선택합니다.
  3. 하나 이상의 사용자 계정에 대한 확인란을 선택합니다.
  4. 사용자 목록 위의 메뉴에서 할당 편집을 선택합니다.
  5. 역할 선택 항목에서 선택한 항목 없음을 선택합니다.
  6. 목록에서 역할을 선택하고 선택 단추를 사용하여 선택합니다.
  7. 화면 아래쪽에 있는 할당 단추를 사용하여 역할을 할당합니다.

Azure Portal에서 각 추가 역할 할당에 대해 ‘사용자를 다시 추가’함으로써 여러 역할이 할당됩니다. 사용자 목록 맨 위에 있는 사용자/그룹 추가 단추를 사용하여 사용자를 다시 추가합니다. 이전 단계를 사용하여 사용자에게 다른 역할을 할당합니다. 사용자(또는 그룹)에 역할을 추가하는 데 필요한 횟수만큼 이 프로세스를 반복할 수 있습니다.

사용자 지정 사용자 계정 섹션에 표시된 CustomAccountFactory은(는) JSON 배열 값을 사용하여 role 클레임에 대해 작동하도록 설정됩니다. 사용자 지정 사용자 계정 섹션에 표시된 대로 CLIENT 앱에 CustomAccountFactory를 추가하고 등록합니다. 원래 role 클레임은 프레임워크에 의해 자동으로 제거되므로 이를 제거하는 코드를 제공할 필요는 없습니다.

Program 클라이언트 앱 파일에서 "appRole"라는 클레임을 검사 대한 ClaimsPrincipal.IsInRole 역할 클레임으로 지정합니다.

builder.Services.AddMsalAuthentication(options =>
{
    ...

    options.UserOptions.RoleClaim = "appRole";
});

참고 항목

directoryRoles 클레임(ADD 관리자 역할)을 사용하려면 RemoteAuthenticationUserOptions.RoleClaim에 "directoryRoles"를 할당합니다.

Program 서버 앱 파일에서 "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"라는 클레임을 검사 대한 ClaimsPrincipal.IsInRole 역할 클레임으로 지정합니다.

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(options =>
    {
        Configuration.Bind("AzureAd", options);
        options.TokenValidationParameters.RoleClaimType = 
            "http://schemas.microsoft.com/ws/2008/06/identity/claims/role";
    },
    options => { Configuration.Bind("AzureAd", options); });

참고 항목

단일 인증 체계가 등록되면 인증 체계가 앱의 기본 체계로 자동으로 사용되며 구성표를 AddAuthentication 또는 AuthenticationOptions을 통해 지정할 필요가 없습니다. 자세한 내용은 ASP.NET Core 인증 개요ASP.NET Core 알림(aspnet/Announcements #490)을 참조하세요.

참고 항목

wids 클레임(ADD 관리자 역할)을 사용하려면 TokenValidationParameters.RoleClaimType에 "wids"를 할당합니다.

이전 단계를 완료하여 사용자(또는 프리미엄 계층 Azure 계정이 있는 경우, 그룹)에 역할을 만들고 할당하고 이 문서의 앞부분과 ASP.NET Core Blazor WebAssembly로 Graph API 사용에서 설명한 대로 Graph SDK를 사용하여 CustomAccountFactory을 구현한 후에는 로그인한 사용자에게 할당된 각 역할(또는 구성원이 속한 그룹에 할당된 역할)에 대한 appRole 클레임이 표시됩니다. 테스트 사용자와 함께 앱을 실행하여 클레임이 예상대로 존재하는지 확인합니다. Graph SDK를 로컬로 테스트할 때, 느린 cookie가 테스트를 방해하지 않도록 각 테스트에 대해 새 프라이빗/시크릿 브라우저 세션을 사용하는 것이 좋습니다. 자세한 내용은 Microsoft Entra ID를 사용하여 ASP.NET Core Blazor WebAssembly 독립 실행형 앱 보안을 참조하세요.

이 시점에서는 구성 요소 권한 부여 방식이 작동합니다. CLIENT 앱의 구성 요소에 있는 권한 부여 메커니즘은 Admin 역할을 사용하여 사용자에게 권한을 부여할 수 있습니다.

여러 역할 테스트가 지원됩니다.

  • 사용자는 AuthorizeView 구성 요소가 있는 Admin또는Developer 역할 중 하나에 있어야 합니다.

    <AuthorizeView Roles="Admin, Developer">
        ...
    </AuthorizeView>
    
  • 사용자는 AuthorizeView 구성 요소가 있는 AdminDeveloper 역할 모두에 있어야 합니다.

    <AuthorizeView Roles="Admin">
        <AuthorizeView Roles="Developer" Context="innerContext">
            ...
        </AuthorizeView>
    </AuthorizeView>
    

    내부 인증에 대한 Context 자세한 내용은 ASP.NET Core Blazor 인증 및 권한 부여를 참조하세요.AuthorizeView

  • 사용자는 [Authorize] 특성이 있는 Admin또는Developer 역할 중 하나에 있어야 합니다.

    @attribute [Authorize(Roles = "Admin, Developer")]
    
  • 사용자는 [Authorize] 특성이 있는 AdminDeveloper 역할 모두에 있어야 합니다.

    @attribute [Authorize(Roles = "Admin")]
    @attribute [Authorize(Roles = "Developer")]
    
  • 사용자는 프로시저 코드가 있는 Admin또는Developer 역할 중 하나에 있어야 합니다.

    @code {
        private async Task DoSomething()
        {
            var authState = await AuthenticationStateProvider
                .GetAuthenticationStateAsync();
            var user = authState.User;
    
            if (user.IsInRole("Admin") || user.IsInRole("Developer"))
            {
                ...
            }
            else
            {
                ...
            }
        }
    }
    
  • 앞의 예제에서 조건부 OR(||)조건부 AND(&&)로 변경하면 사용자가 AdminDeveloper 역할 모두에 있어야 합니다.

    if (user.IsInRole("Admin") && user.IsInRole("Developer"))
    

SERVER 앱의 구성 요소에 있는 권한 부여 메커니즘은 Admin 역할을 사용하여 사용자에게 권한을 부여할 수 있습니다.

여러 역할 테스트가 지원됩니다.

  • 사용자는 [Authorize] 특성이 있는 Admin또는Developer 역할 중 하나에 있어야 합니다.

    [Authorize(Roles = "Admin, Developer")]
    
  • 사용자는 [Authorize] 특성이 있는 AdminDeveloper 역할 모두에 있어야 합니다.

    [Authorize(Roles = "Admin")]
    [Authorize(Roles = "Developer")]
    
  • 사용자는 프로시저 코드가 있는 Admin또는Developer 역할 중 하나에 있어야 합니다.

    static readonly string[] scopeRequiredByApi = new string[] { "API.Access" };
    
    ...
    
    [HttpGet]
    public IEnumerable<ReturnType> Get()
    {
        HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
    
        if (User.IsInRole("Admin") || User.IsInRole("Developer"))
        {
            ...
        }
        else
        {
            ...
        }
    
        return ...
    }
    
  • 앞의 예제에서 조건부 OR(||)조건부 AND(&&)로 변경하면 사용자가 AdminDeveloper 역할 모두에 있어야 합니다.

    if (User.IsInRole("Admin") && User.IsInRole("Developer"))
    

.NET 문자열 비교는 기본적으로 대/소문자를 구분하므로 일치하는 역할 이름도 대/소문자를 구분합니다. 예를 들어, Admin(대문자 A)는 admin(소문자 a)와 동일한 역할로 처리되지 않습니다.

파스칼 사례는 일반적으로 역할 이름(예: BillingAdministrator)에 사용되지만 파스칼 대/소문자를 사용하는 것은 엄격한 요구 사항이 아닙니다. 낙타 케이스, 케밥 케이스 및 뱀 케이스와 같은 다양한 대/소문자 구성표가 허용됩니다. 역할 이름에 공백을 사용하는 것은 비정상적이지만 허용됩니다. 예를 들어 billing administrator은 .NET 앱에서 비정상적인 역할 이름 형식이지만 유효합니다.

추가 리소스