Otorisasi berbasis sumber daya di ASP.NET Core

Pendekatan otorisasi tergantung pada sumber daya. Misalnya, hanya pembuat dokumen yang berwenang untuk memperbarui dokumen. Akibatnya, dokumen harus diambil dari penyimpanan data sebelum evaluasi otorisasi dapat terjadi.

Evaluasi atribut terjadi sebelum pengikatan data dan sebelum eksekusi handler halaman atau tindakan yang memuat dokumen. Untuk alasan ini, otorisasi deklaratif dengan [Authorize] atribut tidak cukup. Sebagai gantinya, Anda dapat memanggil metode otorisasi kustom—gaya yang dikenal sebagai otorisasi imperatif.

Lihat atau unduh sampel kode (cara mengunduh).

Buat aplikasi ASP.NET Core dengan data pengguna yang dilindungi oleh otorisasi berisi aplikasi sampel yang menggunakan otorisasi berbasis sumber daya.

Menggunakan otorisasi imperatif

Otorisasi diimplementasikan sebagai IAuthorizationService layanan dan terdaftar dalam koleksi layanan saat pengaktifan aplikasi. Layanan ini tersedia melalui injeksi dependensi ke penanganan halaman atau tindakan.

public class DocumentController : Controller
{
    private readonly IAuthorizationService _authorizationService;
    private readonly IDocumentRepository _documentRepository;

    public DocumentController(IAuthorizationService authorizationService,
                              IDocumentRepository documentRepository)
    {
        _authorizationService = authorizationService;
        _documentRepository = documentRepository;
    }

IAuthorizationService memiliki dua AuthorizeAsync metode kelebihan beban: satu menerima sumber daya dan nama kebijakan dan yang lain menerima sumber daya dan daftar persyaratan untuk dievaluasi.

Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user,
                          object resource,
                          IEnumerable<IAuthorizationRequirement> requirements);
Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user,
                          object resource,
                          string policyName);

Dalam contoh berikut, sumber daya yang akan diamankan dimuat ke dalam objek kustom Document . Kelebihan AuthorizeAsync beban dipanggil untuk menentukan apakah pengguna saat ini diizinkan untuk mengedit dokumen yang disediakan. Kebijakan otorisasi "EditPolicy" kustom diperhitungkan dalam keputusan. Lihat Otorisasi berbasis kebijakan kustom untuk informasi selengkapnya tentang membuat kebijakan otorisasi.

Catatan

Sampel kode berikut mengasumsikan autentikasi telah menjalankan dan mengatur User properti .

public async Task<IActionResult> OnGetAsync(Guid documentId)
{
    Document = _documentRepository.Find(documentId);

    if (Document == null)
    {
        return new NotFoundResult();
    }

    var authorizationResult = await _authorizationService
            .AuthorizeAsync(User, Document, "EditPolicy");

    if (authorizationResult.Succeeded)
    {
        return Page();
    }
    else if (User.Identity.IsAuthenticated)
    {
        return new ForbidResult();
    }
    else
    {
        return new ChallengeResult();
    }
}

Menulis handler berbasis sumber daya

Menulis handler untuk otorisasi berbasis sumber daya tidak jauh berbeda dengan menulis handler persyaratan biasa. Buat kelas persyaratan kustom, dan terapkan kelas handler persyaratan. Untuk informasi selengkapnya tentang membuat kelas persyaratan, lihat Persyaratan.

Kelas handler menentukan jenis persyaratan dan sumber daya. Misalnya, handler yang SameAuthorRequirement menggunakan dan Document sumber daya mengikuti:

public class DocumentAuthorizationHandler : 
    AuthorizationHandler<SameAuthorRequirement, Document>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                   SameAuthorRequirement requirement,
                                                   Document resource)
    {
        if (context.User.Identity?.Name == resource.Author)
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

public class SameAuthorRequirement : IAuthorizationRequirement { }

Dalam contoh sebelumnya, bayangkan itu SameAuthorRequirement adalah kasus khusus dari kelas yang lebih umum SpecificAuthorRequirement . Kelas SpecificAuthorRequirement (tidak ditampilkan) berisi properti yang Name mewakili nama penulis. Properti Name dapat diatur ke pengguna saat ini.

Daftarkan persyaratan dan handler di Program.cs:

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("EditPolicy", policy =>
        policy.Requirements.Add(new SameAuthorRequirement()));
});

builder.Services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationHandler>();
builder.Services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationCrudHandler>();
builder.Services.AddScoped<IDocumentRepository, DocumentRepository>();

Persyaratan operasional

Jika Anda membuat keputusan berdasarkan hasil operasi CRUD (Buat, Baca, Perbarui, Hapus), gunakan kelas pembantu OperationAuthorizationRequirement . Kelas ini memungkinkan Anda menulis satu handler alih-alih kelas individual untuk setiap jenis operasi. Untuk menggunakannya, berikan beberapa nama operasi:

public static class Operations
{
    public static OperationAuthorizationRequirement Create =
        new OperationAuthorizationRequirement { Name = nameof(Create) };
    public static OperationAuthorizationRequirement Read =
        new OperationAuthorizationRequirement { Name = nameof(Read) };
    public static OperationAuthorizationRequirement Update =
        new OperationAuthorizationRequirement { Name = nameof(Update) };
    public static OperationAuthorizationRequirement Delete =
        new OperationAuthorizationRequirement { Name = nameof(Delete) };
}

Handler diimplementasikan sebagai berikut, menggunakan OperationAuthorizationRequirement persyaratan dan Document sumber daya:

public class DocumentAuthorizationCrudHandler :
    AuthorizationHandler<OperationAuthorizationRequirement, Document>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                   OperationAuthorizationRequirement requirement,
                                                   Document resource)
    {
        if (context.User.Identity?.Name == resource.Author &&
            requirement.Name == Operations.Read.Name)
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

Handler sebelumnya memvalidasi operasi menggunakan sumber daya, identitas pengguna, dan properti persyaratan Name .

Menantang dan melarang penangan sumber daya operasional

Bagian ini menunjukkan bagaimana tantangan dan hasil tindakan terlarang diproses dan bagaimana tantangan dan melarang berbeda.

Untuk memanggil handler sumber daya operasional, tentukan operasi saat memanggil AuthorizeAsync di handler halaman atau tindakan Anda. Contoh berikut menentukan apakah pengguna yang diautentikasi diizinkan untuk melihat dokumen yang disediakan.

Catatan

Sampel kode berikut mengasumsikan autentikasi telah menjalankan dan mengatur User properti .

public async Task<IActionResult> OnGetAsync(Guid documentId)
{
    Document = _documentRepository.Find(documentId);

    if (Document == null)
    {
        return new NotFoundResult();
    }

    var authorizationResult = await _authorizationService
            .AuthorizeAsync(User, Document, Operations.Read);

    if (authorizationResult.Succeeded)
    {
        return Page();
    }
    else if (User.Identity.IsAuthenticated)
    {
        return new ForbidResult();
    }
    else
    {
        return new ChallengeResult();
    }
}

Jika otorisasi berhasil, halaman untuk menampilkan dokumen dikembalikan. Jika otorisasi gagal tetapi pengguna diautentikasi, mengembalikan ForbidResult menginformasikan middleware autentikasi apa pun bahwa otorisasi gagal. ChallengeResult dikembalikan ketika autentikasi harus dilakukan. Untuk klien browser interaktif, mungkin tepat untuk mengalihkan pengguna ke halaman masuk.

Pendekatan otorisasi tergantung pada sumber daya. Misalnya, hanya pembuat dokumen yang berwenang untuk memperbarui dokumen. Akibatnya, dokumen harus diambil dari penyimpanan data sebelum evaluasi otorisasi dapat terjadi.

Evaluasi atribut terjadi sebelum pengikatan data dan sebelum eksekusi handler halaman atau tindakan yang memuat dokumen. Untuk alasan ini, otorisasi deklaratif dengan [Authorize] atribut tidak cukup. Sebagai gantinya, Anda dapat memanggil metode otorisasi kustom—gaya yang dikenal sebagai otorisasi imperatif.

Lihat atau unduh sampel kode (cara mengunduh).

Buat aplikasi ASP.NET Core dengan data pengguna yang dilindungi oleh otorisasi berisi aplikasi sampel yang menggunakan otorisasi berbasis sumber daya.

Menggunakan otorisasi imperatif

Otorisasi diimplementasikan sebagai IAuthorizationService layanan dan terdaftar dalam koleksi layanan dalam Startup kelas . Layanan ini tersedia melalui injeksi dependensi ke penanganan halaman atau tindakan.

public class DocumentController : Controller
{
    private readonly IAuthorizationService _authorizationService;
    private readonly IDocumentRepository _documentRepository;

    public DocumentController(IAuthorizationService authorizationService,
                              IDocumentRepository documentRepository)
    {
        _authorizationService = authorizationService;
        _documentRepository = documentRepository;
    }

IAuthorizationService memiliki dua AuthorizeAsync metode kelebihan beban: satu menerima sumber daya dan nama kebijakan dan yang lain menerima sumber daya dan daftar persyaratan untuk dievaluasi.

Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user,
                          object resource,
                          IEnumerable<IAuthorizationRequirement> requirements);
Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user,
                          object resource,
                          string policyName);

Dalam contoh berikut, sumber daya yang akan diamankan dimuat ke dalam objek kustom Document . Kelebihan AuthorizeAsync beban dipanggil untuk menentukan apakah pengguna saat ini diizinkan untuk mengedit dokumen yang disediakan. Kebijakan otorisasi "EditPolicy" kustom diperhitungkan dalam keputusan. Lihat Otorisasi berbasis kebijakan kustom untuk informasi selengkapnya tentang membuat kebijakan otorisasi.

Catatan

Sampel kode berikut mengasumsikan autentikasi telah menjalankan dan mengatur User properti .

public async Task<IActionResult> OnGetAsync(Guid documentId)
{
    Document = _documentRepository.Find(documentId);

    if (Document == null)
    {
        return new NotFoundResult();
    }

    var authorizationResult = await _authorizationService
            .AuthorizeAsync(User, Document, "EditPolicy");

    if (authorizationResult.Succeeded)
    {
        return Page();
    }
    else if (User.Identity.IsAuthenticated)
    {
        return new ForbidResult();
    }
    else
    {
        return new ChallengeResult();
    }
}

Menulis handler berbasis sumber daya

Menulis handler untuk otorisasi berbasis sumber daya tidak jauh berbeda dengan menulis handler persyaratan biasa. Buat kelas persyaratan kustom, dan terapkan kelas handler persyaratan. Untuk informasi selengkapnya tentang membuat kelas persyaratan, lihat Persyaratan.

Kelas handler menentukan jenis persyaratan dan sumber daya. Misalnya, handler yang SameAuthorRequirement menggunakan dan Document sumber daya mengikuti:

public class DocumentAuthorizationHandler : 
    AuthorizationHandler<SameAuthorRequirement, Document>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                   SameAuthorRequirement requirement,
                                                   Document resource)
    {
        if (context.User.Identity?.Name == resource.Author)
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

public class SameAuthorRequirement : IAuthorizationRequirement { }

Dalam contoh sebelumnya, bayangkan itu SameAuthorRequirement adalah kasus khusus dari kelas yang lebih umum SpecificAuthorRequirement . Kelas SpecificAuthorRequirement (tidak ditampilkan) berisi properti yang Name mewakili nama penulis. Properti Name dapat diatur ke pengguna saat ini.

Daftarkan persyaratan dan handler di Startup.ConfigureServices:

services.AddControllersWithViews();
services.AddRazorPages();

services.AddAuthorization(options =>
{
    options.AddPolicy("EditPolicy", policy =>
        policy.Requirements.Add(new SameAuthorRequirement()));
});

services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationHandler>();
services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationCrudHandler>();
services.AddScoped<IDocumentRepository, DocumentRepository>();

Persyaratan operasional

Jika Anda membuat keputusan berdasarkan hasil operasi CRUD (Buat, Baca, Perbarui, Hapus), gunakan kelas pembantu OperationAuthorizationRequirement . Kelas ini memungkinkan Anda menulis satu handler alih-alih kelas individual untuk setiap jenis operasi. Untuk menggunakannya, berikan beberapa nama operasi:

public static class Operations
{
    public static OperationAuthorizationRequirement Create =
        new OperationAuthorizationRequirement { Name = nameof(Create) };
    public static OperationAuthorizationRequirement Read =
        new OperationAuthorizationRequirement { Name = nameof(Read) };
    public static OperationAuthorizationRequirement Update =
        new OperationAuthorizationRequirement { Name = nameof(Update) };
    public static OperationAuthorizationRequirement Delete =
        new OperationAuthorizationRequirement { Name = nameof(Delete) };
}

Handler diimplementasikan sebagai berikut, menggunakan OperationAuthorizationRequirement persyaratan dan Document sumber daya:

public class DocumentAuthorizationCrudHandler :
    AuthorizationHandler<OperationAuthorizationRequirement, Document>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                   OperationAuthorizationRequirement requirement,
                                                   Document resource)
    {
        if (context.User.Identity?.Name == resource.Author &&
            requirement.Name == Operations.Read.Name)
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

Handler sebelumnya memvalidasi operasi menggunakan sumber daya, identitas pengguna, dan properti persyaratan Name .

Menantang dan melarang penangan sumber daya operasional

Bagian ini menunjukkan bagaimana tantangan dan hasil tindakan terlarang diproses dan bagaimana tantangan dan melarang berbeda.

Untuk memanggil handler sumber daya operasional, tentukan operasi saat memanggil AuthorizeAsync di handler halaman atau tindakan Anda. Contoh berikut menentukan apakah pengguna yang diautentikasi diizinkan untuk melihat dokumen yang disediakan.

Catatan

Sampel kode berikut mengasumsikan autentikasi telah menjalankan dan mengatur User properti .

public async Task<IActionResult> OnGetAsync(Guid documentId)
{
    Document = _documentRepository.Find(documentId);

    if (Document == null)
    {
        return new NotFoundResult();
    }

    var authorizationResult = await _authorizationService
            .AuthorizeAsync(User, Document, Operations.Read);

    if (authorizationResult.Succeeded)
    {
        return Page();
    }
    else if (User.Identity.IsAuthenticated)
    {
        return new ForbidResult();
    }
    else
    {
        return new ChallengeResult();
    }
}

Jika otorisasi berhasil, halaman untuk menampilkan dokumen dikembalikan. Jika otorisasi gagal tetapi pengguna diautentikasi, mengembalikan ForbidResult menginformasikan middleware autentikasi apa pun bahwa otorisasi gagal. ChallengeResult dikembalikan ketika autentikasi harus dilakukan. Untuk klien browser interaktif, mungkin tepat untuk mengalihkan pengguna ke halaman masuk.

Pendekatan otorisasi tergantung pada sumber daya. Misalnya, hanya pembuat dokumen yang berwenang untuk memperbarui dokumen. Akibatnya, dokumen harus diambil dari penyimpanan data sebelum evaluasi otorisasi dapat terjadi.

Evaluasi atribut terjadi sebelum pengikatan data dan sebelum eksekusi handler halaman atau tindakan yang memuat dokumen. Untuk alasan ini, otorisasi deklaratif dengan [Authorize] atribut tidak cukup. Sebagai gantinya, Anda dapat memanggil metode otorisasi kustom—gaya yang dikenal sebagai otorisasi imperatif.

Lihat atau unduh sampel kode (cara mengunduh).

Buat aplikasi ASP.NET Core dengan data pengguna yang dilindungi oleh otorisasi berisi aplikasi sampel yang menggunakan otorisasi berbasis sumber daya.

Menggunakan otorisasi imperatif

Otorisasi diimplementasikan sebagai IAuthorizationService layanan dan terdaftar dalam koleksi layanan dalam Startup kelas . Layanan ini tersedia melalui injeksi dependensi ke penanganan halaman atau tindakan.

public class DocumentController : Controller
{
    private readonly IAuthorizationService _authorizationService;
    private readonly IDocumentRepository _documentRepository;

    public DocumentController(IAuthorizationService authorizationService,
                              IDocumentRepository documentRepository)
    {
        _authorizationService = authorizationService;
        _documentRepository = documentRepository;
    }

IAuthorizationService memiliki dua AuthorizeAsync metode kelebihan beban: satu menerima sumber daya dan nama kebijakan dan yang lain menerima sumber daya dan daftar persyaratan untuk dievaluasi.

Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user,
                          object resource,
                          IEnumerable<IAuthorizationRequirement> requirements);
Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user,
                          object resource,
                          string policyName);

Dalam contoh berikut, sumber daya yang akan diamankan dimuat ke dalam objek kustom Document . Kelebihan AuthorizeAsync beban dipanggil untuk menentukan apakah pengguna saat ini diizinkan untuk mengedit dokumen yang disediakan. Kebijakan otorisasi "EditPolicy" kustom diperhitungkan dalam keputusan. Lihat Otorisasi berbasis kebijakan kustom untuk informasi selengkapnya tentang membuat kebijakan otorisasi.

Catatan

Sampel kode berikut mengasumsikan autentikasi telah menjalankan dan mengatur User properti .

public async Task<IActionResult> OnGetAsync(Guid documentId)
{
    Document = _documentRepository.Find(documentId);

    if (Document == null)
    {
        return new NotFoundResult();
    }

    var authorizationResult = await _authorizationService
            .AuthorizeAsync(User, Document, "EditPolicy");

    if (authorizationResult.Succeeded)
    {
        return Page();
    }
    else if (User.Identity.IsAuthenticated)
    {
        return new ForbidResult();
    }
    else
    {
        return new ChallengeResult();
    }
}

Menulis handler berbasis sumber daya

Menulis handler untuk otorisasi berbasis sumber daya tidak jauh berbeda dengan menulis handler persyaratan biasa. Buat kelas persyaratan kustom, dan terapkan kelas handler persyaratan. Untuk informasi selengkapnya tentang membuat kelas persyaratan, lihat Persyaratan.

Kelas handler menentukan jenis persyaratan dan sumber daya. Misalnya, handler yang SameAuthorRequirement menggunakan dan Document sumber daya mengikuti:

public class DocumentAuthorizationHandler : 
    AuthorizationHandler<SameAuthorRequirement, Document>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                   SameAuthorRequirement requirement,
                                                   Document resource)
    {
        if (context.User.Identity?.Name == resource.Author)
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

public class SameAuthorRequirement : IAuthorizationRequirement { }

Dalam contoh sebelumnya, bayangkan itu SameAuthorRequirement adalah kasus khusus dari kelas yang lebih umum SpecificAuthorRequirement . Kelas SpecificAuthorRequirement (tidak ditampilkan) berisi properti yang Name mewakili nama penulis. Properti Name dapat diatur ke pengguna saat ini.

Daftarkan persyaratan dan handler di Startup.ConfigureServices:

services.AddMvc();

services.AddAuthorization(options =>
{
    options.AddPolicy("EditPolicy", policy =>
        policy.Requirements.Add(new SameAuthorRequirement()));
});

services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationHandler>();
services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationCrudHandler>();
services.AddScoped<IDocumentRepository, DocumentRepository>();

Persyaratan operasional

Jika Anda membuat keputusan berdasarkan hasil operasi CRUD (Buat, Baca, Perbarui, Hapus), gunakan kelas pembantu OperationAuthorizationRequirement . Kelas ini memungkinkan Anda menulis satu handler alih-alih kelas individual untuk setiap jenis operasi. Untuk menggunakannya, berikan beberapa nama operasi:

public static class Operations
{
    public static OperationAuthorizationRequirement Create =
        new OperationAuthorizationRequirement { Name = nameof(Create) };
    public static OperationAuthorizationRequirement Read =
        new OperationAuthorizationRequirement { Name = nameof(Read) };
    public static OperationAuthorizationRequirement Update =
        new OperationAuthorizationRequirement { Name = nameof(Update) };
    public static OperationAuthorizationRequirement Delete =
        new OperationAuthorizationRequirement { Name = nameof(Delete) };
}

Handler diimplementasikan sebagai berikut, menggunakan OperationAuthorizationRequirement persyaratan dan Document sumber daya:

public class DocumentAuthorizationCrudHandler :
    AuthorizationHandler<OperationAuthorizationRequirement, Document>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                   OperationAuthorizationRequirement requirement,
                                                   Document resource)
    {
        if (context.User.Identity?.Name == resource.Author &&
            requirement.Name == Operations.Read.Name)
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

Handler sebelumnya memvalidasi operasi menggunakan sumber daya, identitas pengguna, dan properti persyaratan Name .

Menantang dan melarang penangan sumber daya operasional

Bagian ini menunjukkan bagaimana tantangan dan hasil tindakan terlarang diproses dan bagaimana tantangan dan melarang berbeda.

Untuk memanggil handler sumber daya operasional, tentukan operasi saat memanggil AuthorizeAsync di handler halaman atau tindakan Anda. Contoh berikut menentukan apakah pengguna yang diautentikasi diizinkan untuk melihat dokumen yang disediakan.

Catatan

Sampel kode berikut mengasumsikan autentikasi telah menjalankan dan mengatur User properti .

public async Task<IActionResult> OnGetAsync(Guid documentId)
{
    Document = _documentRepository.Find(documentId);

    if (Document == null)
    {
        return new NotFoundResult();
    }

    var authorizationResult = await _authorizationService
            .AuthorizeAsync(User, Document, Operations.Read);

    if (authorizationResult.Succeeded)
    {
        return Page();
    }
    else if (User.Identity.IsAuthenticated)
    {
        return new ForbidResult();
    }
    else
    {
        return new ChallengeResult();
    }
}

Jika otorisasi berhasil, halaman untuk menampilkan dokumen dikembalikan. Jika otorisasi gagal tetapi pengguna diautentikasi, mengembalikan ForbidResult menginformasikan middleware autentikasi apa pun bahwa otorisasi gagal. ChallengeResult dikembalikan ketika autentikasi harus dilakukan. Untuk klien browser interaktif, mungkin tepat untuk mengalihkan pengguna ke halaman masuk.