Bagikan melalui


Autentikasi dan Otorisasi di ASP.NET Web API

oleh Rick Anderson

Anda telah membuat API web, tetapi sekarang Anda ingin mengontrol akses ke api web tersebut. Dalam rangkaian artikel ini, kita akan melihat beberapa opsi untuk mengamankan API web dari pengguna yang tidak sah. Seri ini akan mencakup autentikasi dan otorisasi.

  • Autentikasi mengetahui identitas pengguna. Misalnya, Alice masuk dengan nama pengguna dan kata sandinya, dan server menggunakan kata sandi untuk mengautentikasi Alice.
  • Otorisasi memutuskan apakah pengguna diizinkan untuk melakukan tindakan. Misalnya, Alice memiliki izin untuk mendapatkan sumber daya tetapi tidak membuat sumber daya.

Artikel pertama dalam seri ini memberikan gambaran umum tentang autentikasi dan otorisasi di ASP.NET Web API. Topik lain menjelaskan skenario autentikasi umum untuk Web API.

Catatan

Terima kasih kepada orang-orang yang meninjau seri ini dan memberikan umpan balik berharga: Rick Anderson, Levi Broderick, Barry Dorrans, Tom Dykstra, Hongmei Ge, David Matson, Daniel Roth, Tim Teebken.

Autentikasi

API Web mengasumsikan bahwa autentikasi terjadi di host. Untuk hosting web, hostnya adalah IIS, yang menggunakan modul HTTP untuk autentikasi. Anda dapat mengonfigurasi proyek untuk menggunakan salah satu modul autentikasi bawaan IIS atau ASP.NET, atau menulis modul HTTP Anda sendiri untuk melakukan autentikasi kustom.

Ketika host mengautentikasi pengguna, host membuat prinsipal, yang merupakan objek IPrincipal yang mewakili konteks keamanan di mana kode berjalan. Host melampirkan prinsipal ke utas saat ini dengan mengatur Thread.CurrentPrincipal. Prinsipal berisi objek Identitas terkait yang berisi informasi tentang pengguna. Jika pengguna diautentikasi, properti Identity.IsAuthenticated mengembalikan true. Untuk permintaan anonim, IsAuthenticated mengembalikan false. Untuk informasi selengkapnya tentang prinsipal, lihat Keamanan Berbasis Peran.

Penangan Pesan HTTP untuk Autentikasi

Alih-alih menggunakan host untuk autentikasi, Anda dapat memasukkan logika autentikasi ke dalam penangan pesan HTTP. Dalam hal ini, penangan pesan memeriksa permintaan HTTP dan mengatur prinsipal.

Kapan Anda harus menggunakan penangan pesan untuk autentikasi? Berikut adalah beberapa tradeoff:

  • Modul HTTP melihat semua permintaan yang melalui alur ASP.NET. Handler pesan hanya melihat permintaan yang dirutekan ke Web API.
  • Anda dapat mengatur penangan pesan per rute, yang memungkinkan Anda menerapkan skema autentikasi ke rute tertentu.
  • Modul HTTP khusus untuk IIS. Penangan pesan bersifat host-agnostik, sehingga dapat digunakan dengan hosting web dan hosting mandiri.
  • Modul HTTP berpartisipasi dalam pengelogan IIS, audit, dan sebagainya.
  • Modul HTTP berjalan sebelumnya di alur. Jika Anda menangani autentikasi di handler pesan, prinsipal tidak diatur hingga handler berjalan. Selain itu, perwakilan kembali ke prinsipal sebelumnya ketika respons meninggalkan penangan pesan.

Umumnya, jika Anda tidak perlu mendukung hosting mandiri, modul HTTP adalah pilihan yang lebih baik. Jika Anda perlu mendukung hosting mandiri, pertimbangkan penanganan pesan.

Mengatur Prinsipal

Jika aplikasi Anda melakukan logika autentikasi kustom, Anda harus mengatur prinsipal di dua tempat:

  • Thread.CurrentPrincipal. Properti ini adalah cara standar untuk mengatur prinsipal utas di .NET.
  • HttpContext.Current.User. Properti ini khusus untuk ASP.NET.

Kode berikut menunjukkan cara mengatur prinsipal:

private void SetPrincipal(IPrincipal principal)
{
    Thread.CurrentPrincipal = principal;
    if (HttpContext.Current != null)
    {
        HttpContext.Current.User = principal;
    }
}

Untuk hosting web, Anda harus mengatur prinsipal di kedua tempat; jika tidak, konteks keamanan mungkin menjadi tidak konsisten. Namun, untuk hosting mandiri, HttpContext.Current null. Untuk memastikan kode Anda adalah host-agnostic, oleh karena itu, periksa null sebelum menetapkan ke HttpContext.Current, seperti yang ditunjukkan.

Authorization

Otorisasi terjadi nanti di alur, lebih dekat ke pengontrol. Itu memungkinkan Anda membuat pilihan yang lebih terperinci saat Anda memberikan akses ke sumber daya.

  • Filter otorisasi berjalan sebelum tindakan pengontrol. Jika permintaan tidak diotorisasi, filter mengembalikan respons kesalahan, dan tindakan tidak dipanggil.
  • Dalam tindakan pengontrol, Anda bisa mendapatkan prinsipal saat ini dari properti ApiController.User . Misalnya, Anda dapat memfilter daftar sumber daya berdasarkan nama pengguna, hanya mengembalikan sumber daya yang termasuk dalam pengguna tersebut.

Diagram alur autentikasi dan otorisasi.

Menggunakan Atribut [Otorisasi]

API Web menyediakan filter otorisasi bawaan, AuthorizeAttribute. Filter ini memeriksa apakah pengguna diautentikasi. Jika tidak, ia mengembalikan kode status HTTP 401 (Tidak Sah), tanpa memanggil tindakan.

Anda dapat menerapkan filter secara global, di tingkat pengontrol, atau pada tingkat tindakan individual.

Secara global: Untuk membatasi akses untuk setiap pengontrol API Web, tambahkan filter AuthorizeAttribute ke daftar filter global:

public static void Register(HttpConfiguration config)
{
    config.Filters.Add(new AuthorizeAttribute());
}

Pengontrol: Untuk membatasi akses untuk pengontrol tertentu, tambahkan filter sebagai atribut ke pengontrol:

// Require authorization for all actions on the controller.
[Authorize]
public class ValuesController : ApiController
{
    public HttpResponseMessage Get(int id) { ... }
    public HttpResponseMessage Post() { ... }
}

Tindakan: Untuk membatasi akses untuk tindakan tertentu, tambahkan atribut ke metode tindakan:

public class ValuesController : ApiController
{
    public HttpResponseMessage Get() { ... }

    // Require authorization for a specific action.
    [Authorize]
    public HttpResponseMessage Post() { ... }
}

Atau, Anda dapat membatasi pengontrol lalu mengizinkan akses anonim ke tindakan tertentu, dengan menggunakan [AllowAnonymous] atribut . Dalam contoh berikut, Post metode dibatasi, tetapi metode ini Get memungkinkan akses anonim.

[Authorize]
public class ValuesController : ApiController
{
    [AllowAnonymous]
    public HttpResponseMessage Get() { ... }

    public HttpResponseMessage Post() { ... }
}

Dalam contoh sebelumnya, filter memungkinkan pengguna yang diautentikasi untuk mengakses metode terbatas; hanya pengguna anonim yang dijaga. Anda juga dapat membatasi akses ke pengguna tertentu atau kepada pengguna dalam peran tertentu:

// Restrict by user:
[Authorize(Users="Alice,Bob")]
public class ValuesController : ApiController
{
}
   
// Restrict by role:
[Authorize(Roles="Administrators")]
public class ValuesController : ApiController
{
}

Catatan

Filter AuthorizeAttribute untuk pengontrol API Web terletak di namespace System.Web.Http . Ada filter serupa untuk pengontrol MVC di namespace System.Web.Mvc , yang tidak kompatibel dengan pengontrol Api Web.

Filter Otorisasi Kustom

Untuk menulis filter otorisasi kustom, berasal dari salah satu jenis berikut:

  • AuthorizeAttribute. Perluas kelas ini untuk melakukan logika otorisasi berdasarkan pengguna saat ini dan peran pengguna.
  • AuthorizationFilterAttribute. Perluas kelas ini untuk melakukan logika otorisasi sinkron yang belum tentu didasarkan pada pengguna atau peran saat ini.
  • IAuthorizationFilter. Terapkan antarmuka ini untuk melakukan logika otorisasi asinkron; misalnya, jika logika otorisasi Anda membuat I/O asinkron atau panggilan jaringan. (Jika logika otorisasi Anda terikat CPU, lebih mudah untuk berasal dari AuthorizationFilterAttribute, karena anda tidak perlu menulis metode asinkron.)

Diagram berikut menunjukkan hierarki kelas untuk kelas AuthorizeAttribute .

Diagram hierarki kelas untuk kelas Otorisasi Atribut.

Diagram hierarki kelas untuk kelas Otorisasi Atribut. Atribut Otorisasi ada di bagian bawah, dengan panah mengarah ke Atribut Filter Otorisasi, dan panah mengarah ke Filter Otorisasi I di bagian atas.

Otorisasi Di Dalam Tindakan Pengontrol

Dalam beberapa kasus, Anda mungkin mengizinkan permintaan untuk melanjutkan, tetapi mengubah perilaku berdasarkan prinsipal. Misalnya, informasi yang Anda kembalikan mungkin berubah tergantung pada peran pengguna. Dalam metode pengontrol, Anda bisa mendapatkan prinsipal saat ini dari properti ApiController.User .

public HttpResponseMessage Get()
{
    if (User.IsInRole("Administrators"))
    {
        // ...
    }
}