Saya mencoba membuat atribut otorisasi khusus di ASP.NET Core. Dalam versi sebelumnya, dimungkinkan untuk mengganti bool AuthorizeCore(HttpContextBase httpContext)
. Tetapi ini tidak lagi ada di AuthorizeAttribute
.
Apa pendekatan saat ini untuk membuat AuthorizeAttribute kustom?
Apa yang ingin saya capai: Saya menerima ID sesi di Header Authorization. Dari ID itu saya akan tahu apakah tindakan tertentu itu valid.
Jawaban:
Pendekatan yang direkomendasikan oleh tim ASP.Net Core adalah dengan menggunakan desain kebijakan baru yang sepenuhnya didokumentasikan di sini . Ide dasar di balik pendekatan baru ini adalah menggunakan atribut [Otorisasi] baru untuk menunjuk "kebijakan" (mis. Di
[Authorize( Policy = "YouNeedToBe18ToDoThis")]
mana kebijakan terdaftar di Startup.cs aplikasi untuk menjalankan beberapa blok kode (yaitu memastikan pengguna memiliki klaim usia) di mana usianya 18 tahun atau lebih).Desain kebijakan adalah tambahan yang bagus untuk kerangka kerja dan tim Inti Keamanan ASP.Net harus dipuji karena pengenalannya. Yang mengatakan, itu tidak cocok untuk semua kasus. Kelemahan dari pendekatan ini adalah bahwa ia gagal memberikan solusi yang nyaman untuk kebutuhan yang paling umum hanya dengan menyatakan bahwa controller atau aksi yang diberikan memerlukan tipe klaim yang diberikan. Dalam kasus di mana aplikasi mungkin memiliki ratusan izin terpisah yang mengatur operasi CRUD pada sumber daya REST individual ("CanCreateOrder", "CanReadOrder", "CanUpdateOrder", "CanDeleteOrder", dll.), Pendekatan baru ini membutuhkan pengulangan satu-ke- satu pemetaan antara nama kebijakan dan nama klaim (mis
options.AddPolicy("CanUpdateOrder", policy => policy.RequireClaim(MyClaimTypes.Permission, "CanUpdateOrder));
), atau menulis beberapa kode untuk melakukan pendaftaran ini pada waktu berjalan (mis. membaca semua jenis klaim dari database dan melakukan panggilan tersebut dalam satu lingkaran). Masalah dengan pendekatan ini untuk sebagian besar kasus adalah bahwa itu tidak perlu overhead.Meskipun tim ASP.Net Core Security merekomendasikan untuk tidak pernah membuat solusi Anda sendiri, dalam beberapa kasus ini mungkin merupakan opsi yang paling bijaksana untuk memulai.
Berikut ini adalah implementasi yang menggunakan IAuthorizationFilter untuk menyediakan cara sederhana untuk mengekspresikan persyaratan klaim untuk kontroler atau tindakan yang diberikan:
sumber
new ForbidResult()
tidak berfungsi (menyebabkan pengecualian / 500) karena tidak memiliki skema otorisasi terkait. Apa yang akan saya gunakan untuk kasus ini?Saya orang keamanan asp.net.
Pertama, izinkan saya meminta maaf bahwa semua ini belum didokumentasikan di luar sampel toko musik atau unit test, dan semuanya masih disempurnakan dalam hal API yang terbuka.Dokumentasi terperinci ada di sini .Kami tidak ingin Anda menulis atribut otorisasi khusus. Jika Anda perlu melakukan itu, kami telah melakukan kesalahan. Sebaliknya, Anda harus menulis persyaratan otorisasi .
Otorisasi bertindak atas Identitas. Identitas dibuat dengan otentikasi.
Anda mengatakan dalam komentar Anda ingin memeriksa ID sesi di header. ID sesi Anda akan menjadi dasar untuk identitas. Jika Anda ingin menggunakan
Authorize
atribut Anda akan menulis middleware otentikasi untuk mengambil header itu dan mengubahnya menjadi dikonfirmasiClaimsPrincipal
. Anda kemudian akan memeriksa di dalam persyaratan otorisasi. Persyaratan otorisasi dapat serumit yang Anda inginkan, misalnya di sini adalah yang mengambil tanggal klaim kelahiran pada identitas saat ini dan akan mengesahkan jika pengguna berusia di atas 18;Kemudian dalam
ConfigureServices()
fungsi Anda, Anda akan menghubungkannyaDan akhirnya, terapkan ke metode kontrol atau tindakan dengan
sumber
ManageStore
Persyaratan dari sampel Toko Musik. Seperti yang ada dalam sampel, hanya ada cara "mengizinkan semua atau tidak sama sekali" untuk melakukannya. Apakah kita kemudian harus membuat kebijakan baru untuk setiap permutasi yang mungkin? yaitu "Pengguna / Baca", "Pengguna / Buat", "Pengguna / AssignRole", "Pengguna / Hapus" jika kita ingin klaim berbutir halus? Kedengarannya seperti pengaturan kerja yang cukup banyak untuk membuatnya bekerja dan banyak kebijakan hanya untuk mengelola klaim daripada[ClaimsAutzorization("User", "Read", "Create", "Delete", "Assign")]
atribut?[CustomAuthorize(Operator.And, Permission.GetUser, Permission.ModifyUser)]
. Saya dapat menggunakan atribut khusus tunggal dalam jumlah tak terbatas hanya dengan memodifikasi parameter konstruktor.IAuthorizeData.Policy
) dan penyedia kebijakan kustom untuk mengatasi pengawasan terang-terangan ini, daripada mengatasinya dalam kerangka kerja. Saya pikir kami tidak seharusnya membuat implementasi kami sendiri? Anda telah membuat beberapa dari kami tidak punya pilihan selain menerapkan kembali otorisasi dari awal (lagi), dan kali ini bahkan tanpa manfaat dariAuthorize
atribut lama Web API . Sekarang kita harus melakukannya pada filter tindakan atau level middleware.Tampaknya dengan ASP.NET Core 2, Anda dapat mewarisi lagi
AuthorizeAttribute
, Anda hanya perlu menerapkanIAuthorizationFilter
(atauIAsyncAuthorizationFilter
):sumber
OnAuthorization
implementasi Anda perlu menunggu metode async, Anda harus menerapkanIAsyncAuthorizationFilter
alih-alihIAuthorizationFilter
jika tidak filter Anda akan dijalankan secara sinkron dan tindakan pengontrol Anda akan mengeksekusi terlepas dari hasil filter.Berdasarkan jawaban Derek Greer HEBAT , saya melakukannya dengan enum.
Ini contoh kode saya:
sumber
Anda dapat membuat AuthorizationHandler Anda sendiri yang akan menemukan atribut khusus pada Pengontrol dan Tindakan Anda, dan meneruskannya ke metode HandleRequirementAsync.
Kemudian Anda dapat menggunakannya untuk atribut khusus apa pun yang Anda butuhkan pada pengontrol atau tindakan Anda. Misalnya menambahkan persyaratan izin. Cukup buat atribut khusus Anda.
Kemudian buat Persyaratan untuk ditambahkan ke Kebijakan Anda
Lalu buat OtorisasiHandler untuk atribut khusus Anda, mewarisi AttributeAuthorizationHandler yang kami buat sebelumnya. Itu akan melewati IEnumerable untuk semua atribut khusus Anda dalam metode HandleRequirementsAsync, diakumulasikan dari Controller dan Action Anda.
Dan akhirnya, dalam metode Startup.cs ConfigureServices Anda, tambahkan AuthorizationHandler kustom Anda ke layanan, dan tambahkan Kebijakan Anda.
Sekarang Anda cukup menghias Pengendali dan Tindakan Anda dengan atribut khusus Anda.
sumber
Mudah: jangan buat sendiri
AuthorizeAttribute
.Untuk skenario otorisasi murni (seperti membatasi akses hanya ke pengguna tertentu), pendekatan yang disarankan adalah menggunakan blok otorisasi baru: https://github.com/aspnet/MusicStore/blob/1c0aeb08bb1ebd846726232226279bbe001782e1/samples/MusicStore/Startupcs## -L92
Untuk otentikasi, sebaiknya ditangani di tingkat middleware.
Apa yang sebenarnya ingin Anda capai?
sumber
Jika ada yang hanya ingin memvalidasi token pembawa di fase otorisasi menggunakan praktik keamanan saat ini yang Anda bisa,
tambahkan ini ke Startup / ConfigureServices Anda
dan ini di basis kode Anda,
Jika kode tidak mencapai
context.Succeed(...)
itu akan gagal (401).Dan kemudian di controller Anda dapat Anda gunakan
sumber
Cara modern adalah AuthenticationHandlers
di startup.cs tambahkan
IUserService adalah layanan yang Anda buat di mana Anda memiliki nama pengguna dan kata sandi. pada dasarnya ia mengembalikan kelas pengguna yang Anda gunakan untuk memetakan klaim Anda.
Kemudian Anda dapat menanyakan klaim ini dan data apa pun yang Anda petakan, ada beberapa, lihat kelas ClaimTypes
Anda dapat menggunakan ini dalam metode ekstensi dan dapatkan pemetaan
Cara baru ini, saya pikir lebih baik daripada
sumber
Pada tulisan ini saya percaya ini dapat dicapai dengan antarmuka IClaimsTransformation di asp.net core 2 dan di atas. Saya baru saja menerapkan bukti konsep yang cukup sharable untuk dikirim ke sini.
Untuk menggunakan ini di Kontroler Anda cukup tambahkan yang sesuai
[Authorize(Roles="whatever")]
dengan metode Anda.Dalam kasus kami, setiap permintaan menyertakan tajuk Otorisasi yang merupakan JWT. Ini adalah prototipe dan saya percaya kami akan melakukan sesuatu yang sangat dekat dengan ini dalam sistem produksi kami minggu depan.
Pemilih masa depan, pertimbangkan tanggal penulisan saat Anda memberikan suara. Mulai hari ini,
works on my machine.
™ ini Anda mungkin ingin lebih banyak penanganan kesalahan dan masuk ke implementasi Anda.sumber
Untuk otorisasi di aplikasi kami. Kami harus memanggil layanan berdasarkan parameter yang diteruskan dalam atribut otorisasi.
Misalnya, jika kami ingin memeriksa apakah dokter yang masuk dapat melihat janji pasien, kami akan memberikan "View_Appointment" untuk atribut otorisasi khusus dan memeriksa hak itu dalam layanan DB dan berdasarkan hasil yang kami akan athorize. Berikut ini kode untuk skenario ini:
Dan pada tindakan API kami menggunakannya seperti ini:
sumber
Jawaban yang diterima ( https://stackoverflow.com/a/41348219/4974715 ) tidak dapat dipertahankan atau cocok secara realistis karena "CanReadResource" digunakan sebagai klaim (tetapi pada dasarnya harus merupakan kebijakan dalam kenyataannya, IMO). Pendekatan pada jawaban tidak OK dalam cara itu digunakan, karena jika metode tindakan memerlukan banyak pengaturan klaim yang berbeda, maka dengan jawaban itu Anda harus berulang kali menulis sesuatu seperti ...
Jadi, bayangkan berapa banyak pengkodean yang akan diambil. Idealnya, "CanReadResource" seharusnya merupakan kebijakan yang menggunakan banyak klaim untuk menentukan apakah pengguna dapat membaca sumber daya.
Apa yang saya lakukan adalah saya membuat kebijakan saya sebagai enumerasi dan kemudian loop melalui dan mengatur persyaratan seperti ...
Kelas DefaultAuthorizationRequirement terlihat seperti ...
Perhatikan bahwa kode di atas juga dapat memungkinkan pra-pemetaan pengguna ke kebijakan di penyimpanan data Anda. Jadi, ketika membuat klaim untuk pengguna, Anda pada dasarnya mengambil kebijakan yang telah dipetakan sebelumnya ke pengguna secara langsung atau tidak langsung (misalnya karena pengguna memiliki nilai klaim tertentu dan bahwa nilai klaim telah diidentifikasi dan dipetakan ke suatu kebijakan, seperti bahwa ia menyediakan pemetaan otomatis untuk pengguna yang memiliki nilai klaim juga), dan mendaftar kebijakan sebagai klaim, sehingga dalam penangan otorisasi, Anda dapat dengan mudah memeriksa apakah klaim pengguna mengandung persyaratan. Kebijakan sebagai Nilai dari item Klaim dalam klaim. Itu untuk cara statis untuk memenuhi persyaratan kebijakan, misalnya persyaratan "Nama depan" cukup statis. Begitu,
Persyaratan dinamis dapat tentang memeriksa rentang usia, dll. Dan kebijakan yang menggunakan persyaratan tersebut tidak dapat dipetakan sebelumnya kepada pengguna.
Contoh pemeriksaan klaim kebijakan dinamis (mis. Untuk memeriksa apakah pengguna berusia di atas 18 tahun) sudah ada di jawaban yang diberikan oleh @blowdart ( https://stackoverflow.com/a/31465227/4974715 ).
PS: Saya mengetik ini di ponsel saya. Maafkan kesalahan ketik dan kurangnya format.
sumber