Öğretici: Dış kiracıda kayıtlı ASP.NET Core web API'lerinin güvenliğini sağlama
Bu öğretici serisi, dış kiracıda kayıtlı bir web API'sinin güvenliğini sağlamayı gösterir. Bu öğreticide, hem temsilci izinleri (kapsamlar) hem de uygulama izinlerini (uygulama rolleri) yayımlayan bir ASP.NET Core web API'sini oluşturacaksınız.
Bu öğreticide;
- Web API'nizi uygulama kayıt ayrıntılarını kullanacak şekilde yapılandırma
- Web API'nizi uygulama kaydında kayıtlı temsilci ve uygulama izinlerini kullanacak şekilde yapılandırma
- Web API'nizin uç noktalarını koruma
Önkoşullar
ToDoList.Read gibi en az bir kapsamı (temsilci izinleri) ve bir uygulama rolünü (uygulama izni) kullanıma sunan bir API kaydı. Henüz yapmadıysanız, kayıt adımlarını izleyerek Microsoft Entra yönetim merkezine bir API kaydedin. Aşağıdakilere sahip olduğunuzdan emin olun:
- Web API'sinin uygulama (istemci) kimliği
- Web API'sinin dizin (kiracı) kimliği kaydedildi
- Web API'sinin kaydedildiği dizin (kiracı) alt etki alanı. Örneğin, birincil etki alanınız contoso.onmicrosoft.com ise, Dizin (kiracı) alt etki alanınız contoso olur.
- Web API'sinin sunduğu temsilci izinleri (kapsamlar) olarak ToDoList.Read ve ToDoList.ReadWrite.
- Web API'sinin sunduğu uygulama izinleri (uygulama rolleri) olarak ToDoList.Read.All ve ToDoList.ReadWrite.All.
.NET 7.0 SDK veya üzeri.
Visual Studio Code veya başka bir kod düzenleyicisi.
ASP.NET Core web API'si oluşturma
Terminalinizi açın ve projenizin yaşamasını istediğiniz klasöre gidin.
Aşağıdaki komutları çalıştırın:
dotnet new webapi -o ToDoListAPI cd ToDoListAPI
Bir iletişim kutusu projeye gerekli varlıkları eklemek isteyip istemediğinizi sorduğunda Evet'i seçin.
Paketleri yükleme
Aşağıdaki paketleri yükleyin:
Microsoft.EntityFrameworkCore.InMemory
Entity Framework Core'un bellek içi veritabanıyla kullanılmasını sağlar. Üretim kullanımı için tasarlanmamıştır.Microsoft.Identity.Web
Microsoft kimlik platformu ile tümleştirilen web uygulamalarına ve web API'lerine kimlik doğrulaması ve yetkilendirme desteği eklemeyi kolaylaştırır.
dotnet add package Microsoft.EntityFrameworkCore.InMemory
dotnet add package Microsoft.Identity.Web
Uygulama kaydı ayrıntılarını yapılandırma
uygulama klasörünüzde appsettings.json dosyasını açın ve web API'nizi kaydettikten sonra kaydettiğiniz uygulama kayıt ayrıntılarını ekleyin.
{
"AzureAd": {
"Instance": "https://Enter_the_Tenant_Subdomain_Here.ciamlogin.com/",
"TenantId": "Enter_the_Tenant_Id_Here",
"ClientId": "Enter_the_Application_Id_Here",
},
"Logging": {...},
"AllowedHosts": "*"
}
Aşağıdaki yer tutucuları gösterildiği gibi değiştirin:
- değerini uygulama (istemci) kimliğiniz ile değiştirin
Enter_the_Application_Id_Here
. - değerini Dizin (kiracı) kimliğiniz ile değiştirin
Enter_the_Tenant_Id_Here
. - değerini Dizin (kiracı) alt etki alanınızla değiştirin
Enter_the_Tenant_Subdomain_Here
.
Özel URL etki alanı kullanma (İsteğe bağlı)
Kimlik doğrulama URL'sini tam olarak markalandıracak özel bir etki alanı kullanın. Kullanıcı açısından bakıldığında, kullanıcılar ciamlogin.com etki alanı adına yeniden yönlendirilmek yerine kimlik doğrulama işlemi sırasında etki alanınızda kalır.
Özel etki alanı kullanmak için şu adımları izleyin:
Dış kiracınızda özel URL etki alanını etkinleştirmek için Dış kiracılardaki uygulamalar için özel URL etki alanlarını etkinleştirme başlığındaki adımları kullanın.
appsettings.json dosyasını açın:
- özelliğinin
Instance
değerini olarak https://Enter_the_Custom_Domain_Here/Enter_the_Tenant_ID_Heregüncelleştirin. değerini özel URL etki alanınızla veEnter_the_Tenant_ID_Here
kiracı kimliğiniz ile değiştirinEnter_the_Custom_Domain_Here
. Kiracı kimliğiniz yoksa kiracı ayrıntılarınızı nasıl okuyacağınızı öğrenin. - [Enter_the_Custom_Domain_Here] değerine sahip özellik ekleyin
knownAuthorities
.
- özelliğinin
appsettings.json dosyanızda değişiklik yaptıktan sonra, özel URL etki alanınız login.contoso.com ve kiracı kimliğiniz aaaabbbb-0000-cccc-1111-dddd2222eeeee ise, dosyanız aşağıdaki kod parçacığına benzer görünmelidir:
{
"AzureAd": {
"Instance": "https://login.contoso.com/aaaabbbb-0000-cccc-1111-dddd2222eeee",
"TenantId": "Enter_the_Tenant_Id_Here",
"ClientId": "Enter_the_Application_Id_Here",
"KnownAuthorities": ["login.contoso.com"]
},
"Logging": {...},
"AllowedHosts": "*"
}
Uygulama rolü ve kapsamı ekleme
İstemci uygulamalarının bir kullanıcı için başarıyla erişim belirteci alabilmesi için tüm API'lerin temsilci izni olarak da adlandırılan en az bir kapsam yayımlaması gerekir. API'ler ayrıca uygulama izinleri olarak da adlandırılan uygulamalar için en az bir uygulama rolü yayımlamalıdır. Bu rol, istemci uygulamalarının bir kullanıcıda oturum açmadıkları bir erişim belirtecini kendileri olarak almasına yöneliktir.
Bu izinleri appsettings.json dosyasında belirtiriz. Bu öğreticide dört izin kaydettik. Temsilci izinleri olarak ToDoList.ReadWrite ve ToDoList.Read ve uygulama izinleri olarak ToDoList.ReadWrite.All ve ToDoList.Read.All .
{
"AzureAd": {
"Instance": "https://Enter_the_Tenant_Subdomain_Here.ciamlogin.com/",
"TenantId": "Enter_the_Tenant_Id_Here",
"ClientId": "Enter_the_Application_Id_Here",
"Scopes": {
"Read": ["ToDoList.Read", "ToDoList.ReadWrite"],
"Write": ["ToDoList.ReadWrite"]
},
"AppPermissions": {
"Read": ["ToDoList.Read.All", "ToDoList.ReadWrite.All"],
"Write": ["ToDoList.ReadWrite.All"]
}
},
"Logging": {...},
"AllowedHosts": "*"
}
Kimlik doğrulama düzeni ekleme
Kimlik doğrulama hizmeti kimlik doğrulaması sırasında yapılandırıldığında bir kimlik doğrulama düzeni adlandırılır. Bu makalede JWT taşıyıcı kimlik doğrulama düzenini kullanacağız. Kimlik doğrulama şeması eklemek için Programs.cs dosyasına aşağıdaki kodu ekleyin.
// Add the following to your imports
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
// Add authentication scheme
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration);
Modellerinizi oluşturma
Projenizin kök klasöründe Models adlı bir klasör oluşturun. klasörüne gidin ve ToDo.cs adlı bir dosya oluşturun ve aşağıdaki kodu ekleyin. Bu kod ToDo adlı bir model oluşturur.
using System;
namespace ToDoListAPI.Models;
public class ToDo
{
public int Id { get; set; }
public Guid Owner { get; set; }
public string Description { get; set; } = string.Empty;
}
Veritabanı bağlamı ekleme
Veritabanı bağlamı, bir veri modeli için Entity Framework işlevselliğini koordine eden ana sınıftır. Bu sınıf, Microsoft.EntityFrameworkCore.DbContext sınıfından türetilerek oluşturulur. Bu öğreticide, test amacıyla bellek içi veritabanı kullanacağız.
Projenin kök klasöründe DbContext adlı bir klasör oluşturun.
Bu klasöre gidin ve ToDoContext.cs adlı bir dosya oluşturun ve ardından bu dosyaya aşağıdaki içeriği ekleyin:
using Microsoft.EntityFrameworkCore; using ToDoListAPI.Models; namespace ToDoListAPI.Context; public class ToDoContext : DbContext { public ToDoContext(DbContextOptions<ToDoContext> options) : base(options) { } public DbSet<ToDo> ToDos { get; set; } }
Uygulamanızın kök klasöründeki Program.cs dosyasını açın ve dosyaya aşağıdaki kodu ekleyin. Bu kod, ASP.NET Core uygulama hizmeti sağlayıcısına (bağımlılık ekleme kapsayıcısı olarak da bilinir) kapsamlı hizmet olarak adlandırılan
ToDoContext
birDbContext
alt sınıfı kaydeder. Bağlam, bellek içi veritabanını kullanacak şekilde yapılandırılır.// Add the following to your imports using ToDoListAPI.Context; using Microsoft.EntityFrameworkCore; builder.Services.AddDbContext<ToDoContext>(opt => opt.UseInMemoryDatabase("ToDos"));
Denetleyici ekleme
Çoğu durumda, denetleyicinin birden fazla eylemi olur. Genellikle Oluşturma, Okuma, Güncelleştirme ve Silme (CRUD) eylemleri. Bu öğreticide yalnızca iki eylem öğesi oluşturacağız. Uç noktalarınızı korumayı göstermek için tüm eylem öğesini okuyun ve eylem öğesi oluşturun.
Projenizin kök klasöründeki Denetleyiciler klasörüne gidin.
Bu klasörün içinde ToDoListController.cs adlı bir dosya oluşturun. Dosyasını açın ve aşağıdaki kazan plakası kodunu ekleyin:
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.Identity.Web; using Microsoft.Identity.Web.Resource; using ToDoListAPI.Models; using ToDoListAPI.Context; namespace ToDoListAPI.Controllers; [Authorize] [Route("api/[controller]")] [ApiController] public class ToDoListController : ControllerBase { private readonly ToDoContext _toDoContext; public ToDoListController(ToDoContext toDoContext) { _toDoContext = toDoContext; } [HttpGet()] [RequiredScopeOrAppPermission()] public async Task<IActionResult> GetAsync(){...} [HttpPost] [RequiredScopeOrAppPermission()] public async Task<IActionResult> PostAsync([FromBody] ToDo toDo){...} private bool RequestCanAccessToDo(Guid userId){...} private Guid GetUserId(){...} private bool IsAppMakingRequest(){...} }
Denetleyiciye kod ekleme
Bu bölümde, oluşturduğumuz yer tutuculara kod ekleyeceğiz. Burada odak, API'yi oluşturmak değil, korumaktır.
Gerekli paketleri içeri aktarın. Microsoft.Identity.Web paketi, kimlik doğrulama mantığını, örneğin belirteç doğrulamasını işleyerek kolayca işlememize yardımcı olan bir MSAL sarmalayıcıdır. Uç noktalarımızın yetkilendirme gerektirdiğinden emin olmak için, yerleşik Microsoft.AspNetCore.Authorization paketini kullanırız.
Bu API'nin çağrılması için kullanıcı adına temsilci izinlerini veya istemcinin kullanıcı adına değil kendi adıyla çağırdığı uygulama izinlerini kullanarak çağrılmasını sağladığımız için, çağrının uygulama tarafından kendi adına yapılıp yapılmadığını bilmek önemlidir. Bunu yapmanın en kolay yolu, erişim belirtecinin isteğe bağlı talebi içerip içermediğini
idtyp
bulma talepleridir. Buidtyp
talep, API'nin belirtecin uygulama belirteci mi yoksa uygulama + kullanıcı belirteci mi olduğunu belirlemesinin en kolay yoludur. İsteğe bağlı talebi etkinleştirmeniziidtyp
öneririz.Talep etkin değilse, erişim belirtecinin
idtyp
roles
bir uygulama belirteci mi yoksa uygulama + kullanıcı belirteci mi olduğunu belirlemek için vescp
taleplerini kullanabilirsiniz. Microsoft Entra Dış Kimlik tarafından verilen erişim belirtecinin iki talep arasında en az biri vardır. Kullanıcıya verilen erişim belirteçlerinde talep bulunurscp
. Bir uygulamaya verilen erişim belirteçlerinde talep bulunurroles
. Her iki talebi de içeren erişim belirteçleri yalnızca kullanıcılara verilir ve bu belirteçler, talebin temsilci izinleri atadığıscp
, talep iseroles
kullanıcının rolünü atadığı kullanıcılara verilir. Hiçbiri olmayan erişim belirteçleri kabul edilmez.private bool IsAppMakingRequest() { if (HttpContext.User.Claims.Any(c => c.Type == "idtyp")) { return HttpContext.User.Claims.Any(c => c.Type == "idtyp" && c.Value == "app"); } else { return HttpContext.User.Claims.Any(c => c.Type == "roles") && !HttpContext.User.Claims.Any(c => c.Type == "scp"); } }
Yapılan isteğin istenen eylemi gerçekleştirmek için yeterli izinler içerip içermediğini belirleyen bir yardımcı işlev ekleyin. İsteği kendi adına yapan uygulamanın mı yoksa kullanıcının kimliğini doğrulayarak verilen kaynağa sahip olan bir kullanıcı adına arama yapıp yapmadığını denetleyin.
private bool RequestCanAccessToDo(Guid userId) { return IsAppMakingRequest() || (userId == GetUserId()); } private Guid GetUserId() { Guid userId; if (!Guid.TryParse(HttpContext.User.GetObjectId(), out userId)) { throw new Exception("User ID is not valid."); } return userId; }
Yolları korumak için izin tanımlarınızı takın. özniteliğini denetleyici sınıfına
[Authorize]
ekleyerek API'nizi koruyun. Bu, denetleyici eylemlerinin yalnızca API yetkili bir kimlikle çağrıldığında çağrılabilmesini sağlar. İzin tanımları, bu eylemleri gerçekleştirmek için gereken izin türlerini tanımlar.[Authorize] [Route("api/[controller]")] [ApiController] public class ToDoListController: ControllerBase{...}
Tüm GET uç noktasına ve POST uç noktasına izinler ekleyin. Bunu, Microsoft.Identity.Web.Resource ad alanının parçası olan RequiredScopeOrAppPermission yöntemini kullanarak yapın. Ardından RequiredScopesConfigurationKey ve RequiredAppPermissionsConfigurationKey öznitelikleri aracılığıyla bu yönteme kapsamları ve izinleri geçirirsiniz.
[HttpGet] [RequiredScopeOrAppPermission( RequiredScopesConfigurationKey = "AzureAD:Scopes:Read", RequiredAppPermissionsConfigurationKey = "AzureAD:AppPermissions:Read" )] public async Task<IActionResult> GetAsync() { var toDos = await _toDoContext.ToDos! .Where(td => RequestCanAccessToDo(td.Owner)) .ToListAsync(); return Ok(toDos); } [HttpPost] [RequiredScopeOrAppPermission( RequiredScopesConfigurationKey = "AzureAD:Scopes:Write", RequiredAppPermissionsConfigurationKey = "AzureAD:AppPermissions:Write" )] public async Task<IActionResult> PostAsync([FromBody] ToDo toDo) { // Only let applications with global to-do access set the user ID or to-do's var ownerIdOfTodo = IsAppMakingRequest() ? toDo.Owner : GetUserId(); var newToDo = new ToDo() { Owner = ownerIdOfTodo, Description = toDo.Description }; await _toDoContext.ToDos!.AddAsync(newToDo); await _toDoContext.SaveChangesAsync(); return Created($"/todo/{newToDo!.Id}", newToDo); }
API'nizi çalıştırma
komutunu kullanarak api'nizin sorunsuz çalıştığından emin olmak için komutunu dotnet run
çalıştırın. Test sırasında bile HTTPS protokolü kullanmayı planlıyorsanız, öğesine güvenmeniz gerekir . NET'in geliştirme sertifikası.
Bu API kodunun tam örneği için örnek dosyasına bakın.