Microsoft ile web API'lerinde yetkilendirme uygulayın. Identity.Web

Bu makalede, Microsoft.Identity.Web kullanarak ASP.NET Core web API'lerinde yetkilendirme uygulayacaksınız. Korumalı kaynaklara erişimi denetlemek için kapsamları (temsilci izinleri) ve uygulama izinlerini (uygulama izinleri) doğrulayacaksınız. Örneklerde kimlik sağlayıcısı olarak Microsoft Entra ID kullanılır.

Yetkilendirme kavramlarını anlama

Bu bölümde kimlik doğrulama ve yetkilendirme arasındaki temel farklar ele alınmakta ve Microsoft.Identity.Web'in erişim belirteçlerinde neyi doğruladığı açıklanmaktadır.

Kimlik doğrulaması ve yetkilendirme karşılaştırması

Konsept Amaç Result
Kimlik Doğrulaması Kimliği doğrulama 401 Başarısız olursa yetkisiz
Authorization İzinleri doğrulama Yetersizse 403 Yasak

Neler doğrulanır?

Bir web API'si erişim belirteci aldığında Microsoft. Identity.Web doğrular:

  1. Jeton imzası - Güvenilir bir otoriteden mi?
  2. Token kitle - Bu API için mi tasarlandı?
  3. Jeton süresi dolma - Hala geçerli mi?
  4. Kapsamlar/Roller - İstemci uygulaması ve konu (kullanıcı) doğru izinlere sahip mi?

Bu kılavuz, kapsamları ve uygulama izinlerini doğrulamak için #4'e odaklanır.

Kapsamlar (temsilci izinleri)

Kapsamlar, kullanıcı bir uygulamaya kendi adına işlem yapma izni verdiğinde (örneğin, oturum açmış bir kullanıcı adına çağrılan bir web API'sinde) uygulanır.

Ayrıntı Değer
Token talebi scp veya scope (istemci uygulaması); roles (kullanıcı)
Örnek değerler "access_as_user", "User.Read", "Files.ReadWrite"

Uygulama izinleri (uygulama izinleri)

Uygulama izinleri, bir uygulama istemci kimlik bilgilerini kullanan bir daemon veya arka plan hizmeti gibi kullanıcı bağlamı olmadan web API'sini kendisi olarak çağırdığında uygulanır.

Ayrıntı Değer
Token talebi roles
Örnek değerler "Mail.Read.All", "User.Read.All"

RequiredScope ile kapsamları doğrulama

özniteliği, RequiredScope erişim belirtecinin belirtilen kapsamlardan en az birini içerdiğini denetler. API'niz yalnızca kullanıcı tarafından atanan isteklere hizmet veriyorsa bu özniteliği kullanın.

Kapsam doğrulamayı ayarlama

API'nizde kapsam doğrulamayı etkinleştirmek için bu adımları izleyin.

1. API'nizde yetkilendirmeyi etkinleştirin:

Uygulama işlem hattınıza kimlik doğrulaması ve yetkilendirme hizmetleri ekleyin:

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));

builder.Services.AddAuthorization(); // Required for authorization

var app = builder.Build();

app.UseAuthentication();
app.UseAuthorization(); // Must be after UseAuthentication
app.MapControllers();

app.Run();

2. Denetleyicileri veya eylemleri koruyun:

[Authorize] ve [RequiredScope] özniteliklerini kontrolcünüz veya bireysel işlemleriniz için uygulayın.

using Microsoft.AspNetCore.Authorization;
using Microsoft.Identity.Web.Resource;

[Authorize]
[RequiredScope("access_as_user")]
public class TodoListController : ControllerBase
{
    [HttpGet]
    public IActionResult GetTodos()
    {
        // Only accessible if token has "access_as_user" scope
        return Ok(new[] { "Todo 1", "Todo 2" });
    }
}

Kapsam desenlerini uygulama

Uygulamanızdaki kapsamları yönetme şeklinize en uygun deseni seçin.

Desen 1: Sabit kodlanmış kapsamlar

Kapsamlar sabitlendiğinde ve geliştirme zamanında bilindiğinde bu düzeni kullanın.

[Authorize]
[RequiredScope("access_as_user")]
public class TodoListController : ControllerBase
{
    // All actions require "access_as_user" scope
}

Birden çok kapsamdan birini kabul etmek için bunları parametre olarak listeleyin:

[Authorize]
[RequiredScope("read", "write", "admin")]
public class TodoListController : ControllerBase
{
    // Token must have "read" OR "write" OR "admin"
}

Kalıp 2: Yapılandırma kapsamları

Kapsamların ortam başına yapılandırılabilir olması gerektiğinde bu düzeni kullanın. Yapılandırma dosyanızda kapsamları tanımlayın:

appsettings.json:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "your-tenant-id",
    "ClientId": "your-api-client-id",
    "Scopes": "access_as_user read write"
  }
}

Denetleyicinizdeki yapılandırma anahtarına başvurun:

[Authorize]
[RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]
public class TodoListController : ControllerBase
{
    // Scopes read from configuration
}

Bu yaklaşım, kapsamları yeniden derlemeden değiştirmenize olanak tanır.

Desen 3: Eylem düzeyi kapsamlar

Farklı eylemler farklı izinler gerektirdiğinde bu düzeni kullanın. Bireysel eylem yöntemlerine [RequiredScope] uygula

[Authorize]
public class TodoListController : ControllerBase
{
    [HttpGet]
    [RequiredScope("read")]
    public IActionResult GetTodos()
    {
        return Ok(todos);
    }

    [HttpPost]
    [RequiredScope("write")]
    public IActionResult CreateTodo([FromBody] Todo todo)
    {
        // Only tokens with "write" scope can create
        return CreatedAtAction(nameof(GetTodos), todo);
    }

    [HttpDelete("{id}")]
    [RequiredScope("admin")]
    public IActionResult DeleteTodo(int id)
    {
        // Only tokens with "admin" scope can delete
        return NoContent();
    }
}

Doğrulama akışını anlama

Bir istek geldiğinde ara yazılım bunu aşağıdaki sırayla işler:

  1. ASP.NET Core kimlik doğrulaması ara yazılımı belirteci doğrular
  2. RequiredScope veya scp talebine yönelik scope öznitelik denetimleri
  3. Belirteç en az bir eşleşen kapsam içeriyorsa istek devam eder.
  4. Eşleşen kapsam bulunmazsa, API bir 403 Yasaklama yanıtı döndürür.

Aşağıdaki örnekte tipik bir hata yanıtı gösterilmektedir:

{
  "error": "insufficient_scope",
  "error_description": "The token does not have the required scope 'access_as_user'."
}

RequiredScopeOrAppPermission ile uygulama izinlerini doğrulama

RequiredScopeOrAppPermission özniteliği kapsamları (temsilci) veya uygulama izinlerini (uygulama) doğrular. API'niz aynı uç noktadan hem kullanıcı tarafından temsilci atanan uygulamalara hem de daemon/hizmet uygulamalarına hizmet veriyorsa bu özniteliği kullanın.

API'niz yalnızca kullanıcı tarafından atanan isteklere hizmet veriyorsa, bunun yerine kullanın RequiredScope .

Kapsam veya uygulama izni doğrulamayı ayarlama

İki belirteç türünü de kabul etmek için özniteliğini uygulayın:

using Microsoft.Identity.Web.Resource;

[Authorize]
[RequiredScopeOrAppPermission(
    AcceptedScope = new[] { "access_as_user" },
    AcceptedAppPermission = new[] { "TodoList.ReadWrite.All" }
)]
public class TodoListController : ControllerBase
{
    [HttpGet]
    public IActionResult GetTodos()
    {
        // Accessible with EITHER:
        // - User-delegated token with "access_as_user" scope, OR
        // - App-only token with "TodoList.ReadWrite.All" app permission
        return Ok(todos);
    }
}

Ayarlardan uygulama izinlerini yapılandırma

Kapsamları ve uygulama izinlerini yeniden derlemeden değiştirmek için yapılandırmada depolayın.

appsettings.json:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "your-tenant-id",
    "ClientId": "your-api-client-id",
    "Scopes": "access_as_user",
    "AppPermissions": "TodoList.ReadWrite.All TodoList.Admin"
  }
}

Denetleyicinizdeki yapılandırma anahtarlarını inceleyin:

[Authorize]
[RequiredScopeOrAppPermission(
    RequiredScopesConfigurationKey = "AzureAd:Scopes",
    RequiredAppPermissionsConfigurationKey = "AzureAd:AppPermissions"
)]
public class TodoListController : ControllerBase
{
    // Scopes and app permissions from configuration
}

Belirteç talebi farklarını karşılaştırma

Aşağıdaki tabloda taleplerin kullanıcı tarafından atanan ve yalnızca uygulama belirteçleri arasında nasıl farklılık gösterdiği gösterilmektedir:

Belirteç Türü İddia Örnek Değer
Kullanıcı tarafından atanan scp veya scope "access_as_user User.Read"
Yalnızca uygulama roles ["TodoList.ReadWrite.All"]

Aşağıdaki örnekte kullanıcı yetkilendirmesiyle oluşturulan bir belirteç gösterilmektedir:

{
  "aud": "api://your-api-client-id",
  "iss": "https://login.microsoftonline.com/.../v2.0",
  "scp": "access_as_user",
  "sub": "user-object-id",
  ...
}

Aşağıdaki örnekte yalnızca uygulama belirteci gösterilmektedir:

{
  "aud": "api://your-api-client-id",
  "iss": "https://login.microsoftonline.com/.../v2.0",
  "roles": ["TodoList.ReadWrite.All"],
  "sub": "app-object-id",
  ...
}

Yetkilendirme ilkeleri oluşturma

Karmaşık yetkilendirme senaryoları için ASP.NET Core yetkilendirme ilkelerini kullanın. İlkeler kuralları merkezileştirmenize, birden çok gereksinimi birleştirmenize ve test edilebilir yetkilendirme mantığı yazmanıza olanak sağlar.

Benefit Description
Merkezi mantık Yetkilendirme kurallarını bir kez tanımlama, her yerde yeniden kullanma
Birleştirilebilir Birden çok gereksinimi birleştirme (kapsamlar + talepler + özel mantık)
Sınanabilir Yetkilendirme mantığının birim testi daha kolay.
Esnek Kapsam doğrulaması dışındaki özel gereksinimler

Desen 1: RequireScope ile ilke tanımlama

Belirli kapsamlar gerektiren adlandırılmış ilkeler tanımlayın ve ardından denetleyicilerinizde bunlara başvurun:

using Microsoft.Identity.Web;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("TodoReadPolicy", policyBuilder =>
    {
        policyBuilder.RequireScope("read", "access_as_user");
    });

    options.AddPolicy("TodoWritePolicy", policyBuilder =>
    {
        policyBuilder.RequireScope("write", "admin");
    });
});

var app = builder.Build();

İlkeleri denetleyici eylemlerine uygulayın:

[Authorize]
public class TodoListController : ControllerBase
{
    [HttpGet]
    [Authorize(Policy = "TodoReadPolicy")]
    public IActionResult GetTodos()
    {
        return Ok(todos);
    }

    [HttpPost]
    [Authorize(Policy = "TodoWritePolicy")]
    public IActionResult CreateTodo([FromBody] Todo todo)
    {
        return CreatedAtAction(nameof(GetTodos), todo);
    }
}

Örnek 2: ScopeAuthorizationRequirement ile politika tanımlama

Daha açık kapsam gereksinimleri için kullanın ScopeAuthorizationRequirement :

using Microsoft.Identity.Web;
using Microsoft.Identity.Web.Resource;

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("CustomPolicy", policyBuilder =>
    {
        policyBuilder.AddRequirements(
            new ScopeAuthorizationRequirement(new[] { "access_as_user" })
        );
    });
});

Desen 3: Varsayılan ilke ayarlama

Tüm [Authorize] özniteliklere otomatik olarak uygulanan bir varsayılan ilke ayarlayın:

builder.Services.AddAuthorization(options =>
{
    var defaultPolicy = new AuthorizationPolicyBuilder()
        .RequireScope("access_as_user")
        .Build();

    options.DefaultPolicy = defaultPolicy;
});

Artık her [Authorize] öznitelik için access_as_user kapsam gereklidir.

[Authorize] // Automatically requires "access_as_user" scope
public class TodoListController : ControllerBase
{
    // All actions protected by default policy
}

Desen 4: Birden çok gereksinimi birleştirme

Kapsam, rol ve kimlik doğrulama gereksinimlerini tek bir ilkede birleştirin:

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("AdminPolicy", policyBuilder =>
    {
        policyBuilder.RequireScope("admin");
        policyBuilder.RequireRole("Admin"); // Also check role claim
        policyBuilder.RequireAuthenticatedUser();
    });
});

Desen 5: Yapılandırmadan ilke oluşturma

İlkeleri ortama özgü tutmak için kapsamları yapılandırmadan yükleyin:

var requiredScopes = builder.Configuration["AzureAd:Scopes"]?.Split(' ');

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("ApiAccessPolicy", policyBuilder =>
    {
        if (requiredScopes != null)
        {
            policyBuilder.RequireScope(requiredScopes);
        }
    });
});

İstekleri kiracıya göre filtreleme

Belirli Microsoft Entra kiracılarından gelen belirteçlere API erişimini kısıtlayın. Bu, çok kiracılı API'nizin yalnızca onaylanan müşteri kiracılarından gelen istekleri kabul etmesi gerektiğinde kullanışlıdır.

İzin verilen kiracılara erişimi kısıtlama

Kiracı kimliği beyanını izin verilenler listesine göre denetleen bir ilke tanımlayın:

builder.Services.AddAuthorization(options =>
{
    string[] allowedTenants =
    {
        "14c2f153-90a7-4689-9db7-9543bf084dad", // Contoso tenant
        "af8cc1a0-d2aa-4ca7-b829-00d361edb652", // Fabrikam tenant
        "979f4440-75dc-4664-b2e1-2cafa0ac67d1"  // Northwind tenant
    };

    options.AddPolicy("AllowedTenantsOnly", policyBuilder =>
    {
        policyBuilder.RequireClaim(
            "http://schemas.microsoft.com/identity/claims/tenantid",
            allowedTenants
        );
    });

    // Apply to all endpoints by default
    options.DefaultPolicy = options.GetPolicy("AllowedTenantsOnly");
});

Ayarlardan kiracı filtrelemeyi yapılandırma

İzin verilen kiracı kimliklerini kod değişikliği olmadan yönetmek için yapılandırmada depolayın.

appsettings.json:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "ClientId": "your-api-client-id",
    "AllowedTenants": [
      "14c2f153-90a7-4689-9db7-9543bf084dad",
      "af8cc1a0-d2aa-4ca7-b829-00d361edb652"
    ]
  }
}

Kiracı listesini okuyun ve başlangıçta ilkeyi oluşturun:

var allowedTenants = builder.Configuration.GetSection("AzureAd:AllowedTenants")
    .Get<string[]>();

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("AllowedTenantsOnly", policyBuilder =>
    {
        policyBuilder.RequireClaim(
            "http://schemas.microsoft.com/identity/claims/tenantid",
            allowedTenants ?? Array.Empty<string>()
        );
    });
});

Kiracı bazlı filtreleme ile kapsamları birleştirme

Hem geçerli bir kapsam hem de onaylı bir kiracı gerektiren bir ilke oluşturun:

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("SecureApiAccess", policyBuilder =>
    {
        // Require specific scope
        policyBuilder.RequireScope("access_as_user");

        // AND require specific tenant
        policyBuilder.RequireClaim(
            "http://schemas.microsoft.com/identity/claims/tenantid",
            allowedTenants
        );
    });
});

En iyi yöntemleri izleyin

Güvenli, sürdürülebilir yetkilendirme mantığı oluşturmak için bu önerileri uygulayın.

Yapılması Gerekenler

1. Her zaman kapsam doğrulaması ile eşleştirin [Authorize] :

[Authorize] // Authentication
[RequiredScope("access_as_user")] // Authorization
public class MyController : ControllerBase { }

2. Ortama özgü kapsamlar için yapılandırmayı kullanın:

[RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]

3. En az ayrıcalık uygula:

[HttpGet]
[RequiredScope("read")] // Only read permission needed

[HttpPost]
[RequiredScope("write")] // Write permission for modifications

4. Karmaşık yetkilendirme için ilkeleri kullanın:

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("AdminOnly", policy =>
    {
        policy.RequireScope("admin");
        policy.RequireClaim("department", "IT");
    });
});

5. Geliştirme sırasında ayrıntılı hata yanıtlarını etkinleştirin:

if (builder.Environment.IsDevelopment())
{
    Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;
}

Yapılmaması Gerekenler

1. [Authorize] kullanırken RequiredScope atlamayın:

//  Wrong - RequiredScope won't work without [Authorize]
[RequiredScope("access_as_user")]
public class MyController : ControllerBase { }

//  Correct
[Authorize]
[RequiredScope("access_as_user")]
public class MyController : ControllerBase { }

2. Üretimde kiracı kimliklerini sabit kodlamayın:

//  Wrong
policyBuilder.RequireClaim("tid", "14c2f153-90a7-4689-9db7-9543bf084dad");

//  Better - use configuration
var tenants = Configuration.GetSection("AllowedTenants").Get<string[]>();
policyBuilder.RequireClaim("tid", tenants);

3. Kapsamları rollerle karıştırmayın:

//  Wrong - This checks roles claim, not scopes
[RequiredScope("Admin")] // "Admin" is typically a role, not a scope

//  Correct
[RequiredScope("access_as_user")] // Scope
[Authorize(Roles = "Admin")] // Role

4. Üretim ortamı hata iletilerinde hassas kapsam bilgilerini ifşa etme:

Üretim ortamları için uygun günlük düzeylerini ve hata işlemeyi yapılandırın.


Yetkilendirme sorunlarını giderme

Yaygın yetkilendirme sorunlarını tanılamak için aşağıdaki kılavuzu kullanın.

403 Yasak - eksik kapsam

Hata: API, geçerli bir belirteçle bile 403 döndürür.

Tanı:

  1. jwt.ms'deki jetonu çözümle.
  2. scp veya scope iddiasını kontrol edin.
  3. Değerin özniteliğinizle eşleştiğinden RequiredScope emin olun.

Çözüm:

  • belirteci alırken istemci uygulamasının doğru kapsamı istediğinden emin olun.
  • kapsamın Microsoft Entra'daki API uygulama kaydında kullanıma sunulduğundan emin olun.
  • Gerekirse yönetici onayı verin.

RequiredScope çalışmıyor

Belirti: Özniteliği yoksayılmış gibi görünüyor.

Denetleyin:

  1. Özniteliğini eklediniz [Authorize] mi?
  2. app.UseAuthorization(), app.UseAuthentication() sonrası mı çağrılır?
  3. Kayıtlı mı services.AddAuthorization() ?

Yapılandırma anahtarı bulunamadı

Hata: Kapsam doğrulaması sessizce başarısız oluyor.

Denetleyin:

{
  "AzureAd": {
    "Scopes": "access_as_user" // Matches RequiredScopesConfigurationKey
  }
}

Yapılandırma yolunun tam olarak eşleştiğinden emin olun.