Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Artikel ini menjelaskan cara menangani permintaan JSON Patch di API web ASP.NET Core.
Dukungan Patch JSON di API web ASP.NET Core didasarkan pada System.Text.Json serialisasi, dan memerlukan Microsoft.AspNetCore.JsonPatch.SystemTextJson paket NuGet.
Apa itu standar JSON Patch?
Standar JSON Patch:
Adalah format standar untuk menjelaskan perubahan yang akan diterapkan ke dokumen JSON.
Didefinisikan dalam RFC 6902 dan banyak digunakan dalam API RESTful untuk melakukan pembaruan parsial pada sumber daya JSON.
Menjelaskan urutan operasi yang mengubah dokumen JSON seperti:
addremovereplacemovecopytest
Di aplikasi web, JSON Patch umumnya digunakan dalam operasi PATCH untuk melakukan pembaruan parsial sumber daya. Daripada mengirim seluruh sumber daya untuk pembaruan, klien dapat mengirim dokumen Patch JSON yang hanya berisi perubahan. Patching mengurangi ukuran payload dan meningkatkan efisiensi.
Untuk gambaran umum standar JSON Patch, lihat jsonpatch.com.
Dukungan JSON Patch di API web ASP.NET Core
Dukungan JSON Patch di API web ASP.NET Core didasarkan pada System.Text.Json serialisasi, dimulai dengan .NET 10, menerapkan Microsoft.AspNetCore.JsonPatch berdasarkan System.Text.Json serialisasi. Fitur ini:
- Memerlukan
Microsoft.AspNetCore.JsonPatch.SystemTextJsonpaket NuGet. - Selaras dengan praktik .NET modern dengan memanfaatkan pustaka System.Text.Json, yang telah dioptimalkan untuk .NET.
- Memberikan peningkatan performa dan pengurangan penggunaan memori dibandingkan dengan implementasi berbasis warisan
Newtonsoft.Json. Untuk informasi selengkapnya tentang implementasi berbasis warisanNewtonsoft.Json, lihat versi .NET 9 dari artikel ini.
Note
Implementasi Microsoft.AspNetCore.JsonPatch berdasarkan serialisasi System.Text.Json bukanlah pengganti langsung untuk implementasi berbasis sistem lama Newtonsoft.Json. Ini tidak mendukung jenis dinamis, misalnya ExpandoObject.
Important
Standar Patch JSON memiliki risiko keamanan yang melekat. Karena risiko ini melekat pada standar Patch JSON, implementasi ASP.NET Core tidak mencoba mengurangi risiko keamanan yang melekat. Ini adalah tanggung jawab pengembang untuk memastikan bahwa dokumen Patch JSON aman untuk diterapkan ke objek target. Untuk informasi selengkapnya, lihat bagian Mitigasi Risiko Keamanan .
Mengaktifkan dukungan JSON Patch dengan System.Text.Json
Untuk mengaktifkan dukungan Patch JSON dengan System.Text.Json, instal Microsoft.AspNetCore.JsonPatch.SystemTextJson paket NuGet.
dotnet add package Microsoft.AspNetCore.JsonPatch.SystemTextJson --prerelease
Paket ini menyediakan JsonPatchDocument<TModel> kelas untuk mewakili dokumen Patch JSON untuk objek jenis T dan logika kustom untuk menserialisasikan dan mendeserialisasi dokumen JSON Patch menggunakan System.Text.Json. Metode kunci kelas JsonPatchDocument<TModel> adalah ApplyTo(Object), yang menerapkan operasi patch ke objek target jenis T.
Kode metode tindakan menerapkan Patch JSON
Dalam pengontrol API, metode tindakan untuk JSON Patch:
- Diannotasikan dengan HttpPatchAttribute atribut .
- JsonPatchDocument<TModel>Menerima , biasanya dengan FromBodyAttribute.
- ApplyTo(Object) Panggilan pada dokumen patch untuk menerapkan perubahan.
Contoh metode Tindakan Pengontrol:
[HttpPatch("{id}", Name = "UpdateCustomer")]
public IActionResult Update(AppDb db, string id, [FromBody] JsonPatchDocument<Customer> patchDoc)
{
// Retrieve the customer by ID
var customer = db.Customers.FirstOrDefault(c => c.Id == id);
// Return 404 Not Found if customer doesn't exist
if (customer == null)
{
return NotFound();
}
patchDoc.ApplyTo(customer, jsonPatchError =>
{
var key = jsonPatchError.AffectedObject.GetType().Name;
ModelState.AddModelError(key, jsonPatchError.ErrorMessage);
}
);
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
return new ObjectResult(customer);
}
Kode dari aplikasi sampel ini berfungsi dengan model-model berikut: Customer dan Order.
namespace App.Models;
public class Customer
{
public string Id { get; set; }
public string? Name { get; set; }
public string? Email { get; set; }
public string? PhoneNumber { get; set; }
public string? Address { get; set; }
public List<Order>? Orders { get; set; }
public Customer()
{
Id = Guid.NewGuid().ToString();
}
}
namespace App.Models;
public class Order
{
public string Id { get; set; }
public DateTime? OrderDate { get; set; }
public DateTime? ShipDate { get; set; }
public decimal TotalAmount { get; set; }
public Order()
{
Id = Guid.NewGuid().ToString();
}
}
Langkah-langkah kunci metode tindakan sampel:
-
Mengambil Data Pelanggan:
- Metode mengambil
Customerobjek dari databaseAppDbmenggunakan id yang disediakan. - Jika tidak ada
Customerobjek yang ditemukan, objek akan mengembalikan404 Not Foundrespons.
- Metode mengambil
-
Terapkan Patch JSON:
- Metode ApplyTo(Object) menerapkan operasi JSON Patch dari patchDoc ke objek
Customeryang diambil. - Jika kesalahan terjadi selama aplikasi patch, seperti operasi atau konflik yang tidak valid, kesalahan tersebut ditangkap oleh delegasi penanganan kesalahan. Delegasi ini menambahkan pesan kesalahan ke
ModelStatemenggunakan nama jenis objek yang terpengaruh dan pesan kesalahan.
- Metode ApplyTo(Object) menerapkan operasi JSON Patch dari patchDoc ke objek
-
Validasi ModelState:
- Setelah menerapkan patch, metode memeriksa
ModelStateuntuk kesalahan. - Jika
ModelStatetidak valid, seperti karena kesalahan patch, maka400 Bad Requestmerespons dengan memberikan kesalahan validasi.
- Setelah menerapkan patch, metode memeriksa
-
Kembalikan Pelanggan yang Diperbarui
- Jika patch berhasil diterapkan dan
ModelStatevalid, metode mengembalikan objek yang diperbaruiCustomerdalam respons.
- Jika patch berhasil diterapkan dan
Contoh respons kesalahan:
Contoh berikut menunjukkan isi 400 Bad Request respons untuk operasi Patch JSON saat jalur yang ditentukan tidak valid:
{
"Customer": [
"The target location specified by path segment 'foobar' was not found."
]
}
Menerapkan dokumen Patch JSON ke objek
Contoh berikut menunjukkan cara menggunakan ApplyTo(Object) metode untuk menerapkan dokumen Patch JSON ke objek.
Contoh: Menerapkan JsonPatchDocument<TModel> ke objek
Contoh berikut menunjukkan:
- Operasi
add,replace, danremove. - Operasi pada properti berlapis.
- Menambahkan item baru ke array.
- Penggunaan Konverter Enum String JSON dalam dokumen patch JSON.
// Original object
var person = new Person {
FirstName = "John",
LastName = "Doe",
Email = "johndoe@gmail.com",
PhoneNumbers = [new() {Number = "123-456-7890", Type = PhoneNumberType.Mobile}],
Address = new Address
{
Street = "123 Main St",
City = "Anytown",
State = "TX"
}
};
// Raw JSON patch document
string jsonPatch = """
[
{ "op": "replace", "path": "/FirstName", "value": "Jane" },
{ "op": "remove", "path": "/Email"},
{ "op": "add", "path": "/Address/ZipCode", "value": "90210" },
{ "op": "add", "path": "/PhoneNumbers/-", "value": { "Number": "987-654-3210",
"Type": "Work" } }
]
""";
// Deserialize the JSON patch document
var patchDoc = JsonSerializer.Deserialize<JsonPatchDocument<Person>>(jsonPatch);
// Apply the JSON patch document
patchDoc!.ApplyTo(person);
// Output updated object
Console.WriteLine(JsonSerializer.Serialize(person, serializerOptions));
Contoh sebelumnya menghasilkan output berikut dari objek yang diperbarui:
{
"firstName": "Jane",
"lastName": "Doe",
"address": {
"street": "123 Main St",
"city": "Anytown",
"state": "TX",
"zipCode": "90210"
},
"phoneNumbers": [
{
"number": "123-456-7890",
"type": "Mobile"
},
{
"number": "987-654-3210",
"type": "Work"
}
]
}
Metode ApplyTo(Object) ini umumnya mengikuti konvensi dan opsi System.Text.Json untuk memproses JsonPatchDocument<TModel>, termasuk perilaku yang dikontrol oleh opsi berikut:
- JsonNumberHandling: Apakah properti numerik ditafsirkan dari string.
- PropertyNameCaseInsensitive: Apakah nama properti peka huruf besar/kecil.
Perbedaan utama antara System.Text.Json dan implementasi baru JsonPatchDocument<TModel> :
- Jenis runtime objek target, bukan jenis yang dideklarasikan, menentukan patch properti ApplyTo(Object) mana.
- System.Text.Json deserialisasi bergantung pada jenis yang dinyatakan untuk mengidentifikasi properti yang memenuhi syarat.
Contoh: Menerapkan JsonPatchDocument dengan penanganan kesalahan
Ada berbagai kesalahan yang dapat terjadi saat menerapkan dokumen Patch JSON. Misalnya, objek target mungkin tidak memiliki properti yang ditentukan, atau nilai yang ditentukan mungkin tidak kompatibel dengan jenis properti.
JSON Patch mendukung test operasi, yang memeriksa apakah nilai tertentu sama dengan properti target. Jika tidak, itu akan mengembalikan kesalahan.
Contoh berikut menunjukkan cara menangani kesalahan ini dengan anggun.
Important
Objek yang diteruskan ke metode ApplyTo(Object) dimodifikasi langsung di tempatnya. Pemanggil bertanggung jawab dalam mengabaikan perubahan jika ada operasi yang gagal.
// Original object
var person = new Person {
FirstName = "John",
LastName = "Doe",
Email = "johndoe@gmail.com"
};
// Raw JSON patch document
string jsonPatch = """
[
{ "op": "replace", "path": "/Email", "value": "janedoe@gmail.com"},
{ "op": "test", "path": "/FirstName", "value": "Jane" },
{ "op": "replace", "path": "/LastName", "value": "Smith" }
]
""";
// Deserialize the JSON patch document
var patchDoc = JsonSerializer.Deserialize<JsonPatchDocument<Person>>(jsonPatch);
// Apply the JSON patch document, catching any errors
Dictionary<string, string[]>? errors = null;
patchDoc!.ApplyTo(person, jsonPatchError =>
{
errors ??= new ();
var key = jsonPatchError.AffectedObject.GetType().Name;
if (!errors.ContainsKey(key))
{
errors.Add(key, new string[] { });
}
errors[key] = errors[key].Append(jsonPatchError.ErrorMessage).ToArray();
});
if (errors != null)
{
// Print the errors
foreach (var error in errors)
{
Console.WriteLine($"Error in {error.Key}: {string.Join(", ", error.Value)}");
}
}
// Output updated object
Console.WriteLine(JsonSerializer.Serialize(person, serializerOptions));
Contoh sebelumnya menghasilkan output berikut:
Error in Person: The current value 'John' at path 'FirstName' is not equal
to the test value 'Jane'.
{
"firstName": "John",
"lastName": "Smith", <<< Modified!
"email": "janedoe@gmail.com", <<< Modified!
"phoneNumbers": []
}
Mengurangi risiko keamanan
Saat menggunakan Microsoft.AspNetCore.JsonPatch.SystemTextJson paket, sangat penting untuk memahami dan mengurangi potensi risiko keamanan. Bagian berikut menguraikan risiko keamanan yang diidentifikasi yang terkait dengan Patch JSON dan memberikan mitigasi yang direkomendasikan untuk memastikan penggunaan paket yang aman.
Important
Ini bukan daftar ancaman yang lengkap. Pengembang aplikasi harus melakukan tinjauan model ancaman mereka sendiri untuk menentukan daftar komprehensif khusus aplikasi dan membuat mitigasi yang sesuai kebutuhan. Misalnya, aplikasi yang mengekspos koleksi ke operasi patch harus mempertimbangkan potensi serangan kompleksitas algoritma jika operasi tersebut menyisipkan atau menghapus elemen di awal koleksi.
Untuk meminimalkan risiko keamanan saat mengintegrasikan fungsionalitas JSON Patch ke dalam aplikasi mereka, pengembang harus:
- Jalankan model ancaman komprehensif untuk aplikasi mereka sendiri.
- Mengatasi ancaman yang diidentifikasi.
- Ikuti mitigasi yang direkomendasikan di bagian berikut.
Penolakan Layanan (DoS) melalui amplifikasi memori
-
Skenario: Klien berbahaya mengirimkan
copyoperasi yang menduplikasi grafik objek besar beberapa kali, yang mengarah ke konsumsi memori yang berlebihan. - Dampak: Potensi kondisi Out-Of-Memory (OOM), menyebabkan gangguan layanan.
-
Mitigation:
- Validasi dokumen JSON Patch masuk untuk ukuran dan struktur sebelum memanggil ApplyTo(Object).
- Validasi harus spesifik untuk aplikasi, tetapi contoh validasi dapat terlihat mirip dengan yang berikut ini:
public void Validate(JsonPatchDocument<T> patch)
{
// This is just an example. It's up to the developer to make sure that
// this case is handled properly, based on the app needs.
if (patch.Operations.Where(op=>op.OperationType == OperationType.Copy).Count()
> MaxCopyOperationsCount)
{
throw new InvalidOperationException();
}
}
Pengacauan Logika Bisnis
- Skenario: Operasi patch dapat memanipulasi bidang dengan invarian implisit (misalnya, bendera internal, ID, atau bidang komputasi), melanggar batasan bisnis.
- Dampak: Masalah integritas data dan perilaku aplikasi yang tidak diinginkan.
-
Mitigation:
- Gunakan POCO (Objek CLR Lama Biasa) dengan properti yang ditentukan secara eksplisit yang aman untuk dimodifikasi.
- Hindari mengekspos properti sensitif atau kritis keamanan di objek target.
- Jika objek POCO tidak digunakan, validasi objek yang di-patch setelah menerapkan operasi untuk memastikan aturan bisnis dan invarian tidak dilanggar.
- Gunakan POCO (Objek CLR Lama Biasa) dengan properti yang ditentukan secara eksplisit yang aman untuk dimodifikasi.
Autentikasi dan otorisasi
- Skenario: Klien yang tidak diautentikasi atau tidak sah mengirim permintaan Patch JSON berbahaya.
- Dampak: Akses tidak sah untuk memodifikasi data sensitif atau mengganggu perilaku aplikasi.
-
Mitigation:
- Lindungi titik akhir yang menerima permintaan JSON Patch dengan mekanisme autentikasi dan otorisasi yang tepat.
- Batasi akses ke klien atau pengguna tepercaya dengan izin yang sesuai.
Mendapatkan kode
Melihat atau mengunduh kode sampel. (Cara mengunduh).
Untuk menguji sampel, jalankan aplikasi dan kirim permintaan HTTP dengan pengaturan berikut:
- URL:
http://localhost:{port}/jsonpatch/jsonpatchwithmodelstate - Metode HTTP:
PATCH - Judul:
Content-Type: application/json-patch+json - Isi: Salin dan tempel salah satu sampel dokumen patch JSON dari folder proyek JSON .
Sumber daya tambahan
Artikel ini menjelaskan cara menangani permintaan JSON Patch di API web ASP.NET Core.
Important
Standar Patch JSON memiliki risiko keamanan yang melekat. Implementasi ini tidak mencoba mengurangi risiko keamanan yang melekat ini. Ini adalah tanggung jawab pengembang untuk memastikan bahwa dokumen Patch JSON aman untuk diterapkan ke objek target. Untuk informasi selengkapnya, lihat bagian Mitigasi Risiko Keamanan .
Penginstalan paket
Dukungan JSON Patch di API web ASP.NET Core didasarkan pada Newtonsoft.Json dan memerlukan Microsoft.AspNetCore.Mvc.NewtonsoftJson paket NuGet.
Untuk mengaktifkan dukungan JSON Patch:
Microsoft.AspNetCore.Mvc.NewtonsoftJsonInstal paket NuGet.Panggil AddNewtonsoftJson. Contohnya:
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers() .AddNewtonsoftJson(); var app = builder.Build(); app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();
AddNewtonsoftJson menggantikan pemformat input dan output berbasis default System.Text.Jsonyang digunakan untuk memformat semua konten JSON. Metode ekstensi ini kompatibel dengan metode pendaftaran layanan MVC berikut:
JsonPatch memerlukan pengaturan Content-Type header ke application/json-patch+json.
Menambahkan dukungan untuk JSON Patch saat menggunakan System.Text.Json
Formatter System.Text.Jsoninput berbasis tidak mendukung JSON Patch. Untuk menambahkan dukungan untuk JSON Patch menggunakan Newtonsoft.Json, sambil membiarkan pemformat input dan output lainnya tidak berubah:
Microsoft.AspNetCore.Mvc.NewtonsoftJsonInstal paket NuGet.Perbarui
Program.cs:using JsonPatchSample; using Microsoft.AspNetCore.Mvc.Formatters; var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(options => { options.InputFormatters.Insert(0, MyJPIF.GetJsonPatchInputFormatter()); }); var app = builder.Build(); app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.Extensions.Options; namespace JsonPatchSample; public static class MyJPIF { public static NewtonsoftJsonPatchInputFormatter GetJsonPatchInputFormatter() { var builder = new ServiceCollection() .AddLogging() .AddMvc() .AddNewtonsoftJson() .Services.BuildServiceProvider(); return builder .GetRequiredService<IOptions<MvcOptions>>() .Value .InputFormatters .OfType<NewtonsoftJsonPatchInputFormatter>() .First(); } }
Kode sebelumnya membuat instans NewtonsoftJsonPatchInputFormatter dan menyisipkannya sebagai entri pertama dalam MvcOptions.InputFormatters koleksi. Urutan pendaftaran ini memastikan bahwa:
-
NewtonsoftJsonPatchInputFormattermemproses permintaan Patch JSON. - Input dan formatter berbasis yang ada
System.Text.Jsonmemproses semua permintaan dan respons JSON lainnya.
Newtonsoft.Json.JsonConvert.SerializeObject Gunakan metode untuk membuat JsonPatchDocumentserialisasi .
Metode permintaan HTTP PATCH
Metode PUT dan PATCH digunakan untuk memperbarui sumber daya yang ada. Perbedaannya adalah PUT menggantikan seluruh sumber daya, sementara PATCH hanya menentukan perubahan.
JSON Patch
JSON Patch adalah format untuk menentukan pembaruan yang akan diterapkan ke sumber daya. Dokumen JSON Patch memiliki array operasi. Setiap operasi mengidentifikasi jenis perubahan tertentu. Contoh perubahan tersebut termasuk menambahkan elemen array atau mengganti nilai properti.
Misalnya, dokumen JSON berikut mewakili sumber daya, dokumen Patch JSON untuk sumber daya, dan hasil penerapan operasi Patch.
Contoh sumber daya
{
"customerName": "John",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
}
]
}
Contoh patch JSON
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Dalam JSON sebelumnya:
- Properti
opmenunjukkan jenis operasi. - Properti
pathmenunjukkan elemen yang akan diperbarui. - Properti
valuemenyediakan nilai baru.
Sumber daya setelah patch
Berikut adalah sumber daya setelah menerapkan dokumen Patch JSON sebelumnya:
{
"customerName": "Barry",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
},
{
"orderName": "Order2",
"orderType": null
}
]
}
Perubahan yang dilakukan dengan menerapkan dokumen JSON Patch ke sumber daya adalah atomik. Jika ada operasi dalam daftar yang gagal, tidak ada operasi dalam daftar yang diterapkan.
Sintaks jalur
Properti jalur objek operasi memiliki garis miring antar level. Contohnya,"/address/zipCode".
Indeks berbasis nol digunakan untuk menentukan elemen array. Elemen pertama dari addresses array akan berada di /addresses/0. Untuk add ke akhir array, gunakan tanda hubung (-) daripada nomor indeks: /addresses/-.
Operations
Tabel berikut ini memperlihatkan operasi yang didukung seperti yang didefinisikan dalam spesifikasi Patch JSON:
| Operation | Notes |
|---|---|
add |
Tambahkan elemen properti atau array. Untuk properti yang ada: tetapkan nilai. |
remove |
Menghapus elemen properti atau array. |
replace |
Sama seperti remove diikuti oleh add di lokasi yang sama. |
move |
Sama seperti remove dari sumber diikuti oleh add ke tujuan menggunakan nilai dari sumber. |
copy |
Sama seperti add tujuan menggunakan nilai dari sumber. |
test |
Mengembalikan kode status keberhasilan jika nilai di path = disediakan value. |
Patch JSON di ASP.NET Core
Implementasi ASP.NET Core dari JSON Patch disediakan dalam paket NuGet Microsoft.AspNetCore.JsonPatch .
Kode metode tindakan
Dalam pengontrol API, metode tindakan untuk JSON Patch:
- Diannotasikan dengan
HttpPatchatribut . -
JsonPatchDocument<TModel>Menerima , biasanya dengan
[FromBody]. - ApplyTo(Object) Panggilan pada dokumen patch untuk menerapkan perubahan.
Berikut contohnya:
[HttpPatch]
public IActionResult JsonPatchWithModelState(
[FromBody] JsonPatchDocument<Customer> patchDoc)
{
if (patchDoc != null)
{
var customer = CreateCustomer();
patchDoc.ApplyTo(customer, ModelState);
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
return new ObjectResult(customer);
}
else
{
return BadRequest(ModelState);
}
}
Kode dari aplikasi sampel ini berfungsi dengan model berikut Customer :
namespace JsonPatchSample.Models;
public class Customer
{
public string? CustomerName { get; set; }
public List<Order>? Orders { get; set; }
}
namespace JsonPatchSample.Models;
public class Order
{
public string OrderName { get; set; }
public string OrderType { get; set; }
}
Metode tindakan sampel:
- Membangun sebuah
Customer. - Menerapkan patch.
- Mengembalikan hasil dalam isi respons.
Dalam aplikasi nyata, kode akan mengambil data dari penyimpanan seperti database dan memperbarui database setelah menerapkan patch.
Status model
Contoh metode tindakan sebelumnya memanggil kelebihan beban ApplyTo yang mengambil status model sebagai salah satu parameternya. Dengan opsi ini, Anda bisa mendapatkan pesan kesalahan sebagai respons. Contoh berikut menunjukkan isi respons Permintaan Buruk 400 untuk test operasi:
{
"Customer": [
"The current value 'John' at path 'customerName' != test value 'Nancy'."
]
}
Objek dinamis
Contoh metode tindakan berikut menunjukkan cara menerapkan patch ke objek dinamis:
[HttpPatch]
public IActionResult JsonPatchForDynamic([FromBody]JsonPatchDocument patch)
{
dynamic obj = new ExpandoObject();
patch.ApplyTo(obj);
return Ok(obj);
}
Operasi tambahkan
- Jika
pathmenunjuk ke elemen array: menyisipkan elemen baru sebelum elemen yang ditentukan olehpath. - Jika
pathmenunjuk ke properti: mengatur nilai properti. - Jika
pathmenunjuk ke lokasi yang tidak ada:- Jika sumber daya yang akan di-patch adalah objek dinamis: menambahkan properti.
- Jika sumber daya untuk di-patch adalah objek statis: permintaan gagal.
Contoh dokumen patch berikut mengatur nilai CustomerName dan menambahkan Order objek ke akhir Orders array.
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Operasi hapus
- Jika
pathmenunjuk ke elemen array: menghapus elemen . - Jika
pathmenunjuk ke properti:- Jika sumber daya untuk patch adalah objek dinamis: menghapus properti .
- Jika sumber daya untuk di-patch adalah objek statis:
- Jika properti nullable: mengaturnya ke null.
- Jika properti tidak dapat diubah ke null, atur ke
default<T>.
Contoh kumpulan CustomerName dokumen patch berikut ke null dan hapus Orders[0]:
[
{
"op": "remove",
"path": "/customerName"
},
{
"op": "remove",
"path": "/orders/0"
}
]
Operasi ganti
Operasi ini secara fungsional sama remove dengan diikuti oleh add.
Contoh dokumen patch berikut menetapkan nilai CustomerName dan mengganti Orders[0]dengan objek baru Order :
[
{
"op": "replace",
"path": "/customerName",
"value": "Barry"
},
{
"op": "replace",
"path": "/orders/0",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Operasi pemindahan
- Jika
pathmenunjuk ke elemen array: menyalinfromelemen ke lokasipathelemen, maka menjalankanremoveoperasi padafromelemen . - Jika
pathmenunjuk ke properti: menyalin nilaifromproperti kepathproperti, maka menjalankanremoveoperasi padafromproperti . - Jika
pathmenunjuk ke properti yang tidak ada:- Jika sumber daya untuk di-patch adalah objek statis: permintaan gagal.
- Jika sumber daya untuk patch adalah objek dinamis: menyalin
fromproperti ke lokasi yangpathditunjukkan olehremove, maka menjalankan operasi padafromproperti .
Contoh dokumen patch berikut:
- Menyalin nilai
Orders[0].OrderNamekeCustomerName. -
Orders[0].OrderNameMengatur ke null. -
Orders[1]Pindah ke sebelumOrders[0].
[
{
"op": "move",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "move",
"from": "/orders/1",
"path": "/orders/0"
}
]
Operasi salin
Operasi ini secara fungsional sama move dengan operasi tanpa langkah terakhir remove .
Contoh dokumen patch berikut:
- Menyalin nilai
Orders[0].OrderNamekeCustomerName. - Menyisipkan salinan
Orders[1]sebelumOrders[0].
[
{
"op": "copy",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "copy",
"from": "/orders/1",
"path": "/orders/0"
}
]
Operasi pengujian
Jika nilai di lokasi yang ditunjukkan oleh path berbeda dari nilai yang disediakan dalam value, permintaan gagal. Dalam hal ini, seluruh permintaan PATCH gagal bahkan jika semua operasi lain dalam dokumen patch akan berhasil.
Operasi test ini umumnya digunakan untuk mencegah pembaruan ketika ada konflik konkurensi.
Contoh dokumen patch berikut tidak berpengaruh jika nilai CustomerName awal adalah "John", karena pengujian gagal:
[
{
"op": "test",
"path": "/customerName",
"value": "Nancy"
},
{
"op": "add",
"path": "/customerName",
"value": "Barry"
}
]
Mendapatkan kode
Melihat atau mengunduh kode sampel. (Cara mengunduh).
Untuk menguji sampel, jalankan aplikasi dan kirim permintaan HTTP dengan pengaturan berikut:
- URL:
http://localhost:{port}/jsonpatch/jsonpatchwithmodelstate - Metode HTTP:
PATCH - Judul:
Content-Type: application/json-patch+json - Isi: Salin dan tempel salah satu sampel dokumen patch JSON dari folder proyek JSON .
Mengurangi risiko keamanan
Saat menggunakan paket Microsoft.AspNetCore.JsonPatch dengan implementasi berbasis Newtonsoft.Json, memahami dan mengurangi potensi risiko keamanan adalah sangat penting. Bagian berikut menguraikan risiko keamanan yang diidentifikasi yang terkait dengan Patch JSON dan memberikan mitigasi yang direkomendasikan untuk memastikan penggunaan paket yang aman.
Important
Ini bukan daftar ancaman yang lengkap. Pengembang aplikasi harus melakukan tinjauan model ancaman mereka sendiri untuk menentukan daftar komprehensif khusus aplikasi dan membuat mitigasi yang sesuai kebutuhan. Misalnya, aplikasi yang mengekspos koleksi ke operasi patch harus mempertimbangkan potensi serangan kompleksitas algoritma jika operasi tersebut menyisipkan atau menghapus elemen di awal koleksi.
Dengan menjalankan model ancaman komprehensif untuk aplikasi mereka sendiri dan mengatasi ancaman yang diidentifikasi saat mengikuti mitigasi yang direkomendasikan di bawah ini, konsumen paket ini dapat mengintegrasikan fungsionalitas JSON Patch ke dalam aplikasi mereka sambil meminimalkan risiko keamanan.
Penolakan Layanan (DoS) melalui amplifikasi memori
-
Skenario: Klien berbahaya mengirimkan
copyoperasi yang menduplikasi grafik objek besar beberapa kali, yang mengarah ke konsumsi memori yang berlebihan. - Dampak: Potensi kondisi Out-Of-Memory (OOM), menyebabkan gangguan layanan.
-
Mitigation:
- Validasi dokumen JSON Patch masuk untuk ukuran dan struktur sebelum memanggil
ApplyTo. - Validasi harus spesifik untuk aplikasi, tetapi contoh validasi dapat terlihat mirip dengan yang berikut ini:
- Validasi dokumen JSON Patch masuk untuk ukuran dan struktur sebelum memanggil
public void Validate(JsonPatchDocument patch)
{
// This is just an example. It's up to the developer to make sure that
// this case is handled properly, based on the app needs.
if (patch.Operations.Where(op => op.OperationType == OperationType.Copy).Count()
> MaxCopyOperationsCount)
{
throw new InvalidOperationException();
}
}
Pengacauan Logika Bisnis
- Skenario: Operasi patch dapat memanipulasi bidang dengan invarian implisit (misalnya, bendera internal, ID, atau bidang komputasi), melanggar batasan bisnis.
- Dampak: Masalah integritas data dan perilaku aplikasi yang tidak diinginkan.
-
Mitigation:
- Gunakan objek POCO dengan properti yang ditentukan secara eksplisit yang aman untuk dimodifikasi.
- Hindari mengekspos properti sensitif atau kritis keamanan di objek target.
- Jika tidak ada objek POCO yang digunakan, validasi objek yang di-patch setelah menerapkan operasi untuk memastikan aturan bisnis dan invarian tidak dilanggar.
Autentikasi dan otorisasi
- Skenario: Klien yang tidak diautentikasi atau tidak sah mengirim permintaan Patch JSON berbahaya.
- Dampak: Akses tidak sah untuk memodifikasi data sensitif atau mengganggu perilaku aplikasi.
-
Mitigation:
- Lindungi titik akhir yang menerima permintaan JSON Patch dengan mekanisme autentikasi dan otorisasi yang tepat.
- Batasi akses ke klien atau pengguna tepercaya dengan izin yang sesuai.
Sumber daya tambahan
Artikel ini menjelaskan cara menangani permintaan JSON Patch di API web ASP.NET Core.
Important
Standar Patch JSON memiliki risiko keamanan yang melekat. Karena risiko ini melekat pada standar Patch JSON, implementasi ini tidak mencoba mengurangi risiko keamanan yang melekat. Ini adalah tanggung jawab pengembang untuk memastikan bahwa dokumen Patch JSON aman untuk diterapkan ke objek target. Untuk informasi selengkapnya, lihat bagian Mitigasi Risiko Keamanan .
Penginstalan paket
Untuk mengaktifkan dukungan JSON Patch di aplikasi Anda, selesaikan langkah-langkah berikut:
Microsoft.AspNetCore.Mvc.NewtonsoftJsonInstal paket NuGet.Perbarui metode proyek
Startup.ConfigureServicesuntuk memanggil AddNewtonsoftJson. Contohnya:services .AddControllersWithViews() .AddNewtonsoftJson();
AddNewtonsoftJson kompatibel dengan metode pendaftaran layanan MVC:
JSON Patch, AddNewtonsoftJson, dan System.Text.Json
AddNewtonsoftJson menggantikan System.Text.Jsonpemformat input dan output berbasis yang digunakan untuk memformat semua konten JSON. Untuk menambahkan dukungan untuk JSON Patch menggunakan Newtonsoft.Json, sambil membiarkan formatter lain tidak berubah, perbarui metode proyek Startup.ConfigureServices sebagai berikut:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews(options =>
{
options.InputFormatters.Insert(0, GetJsonPatchInputFormatter());
});
}
private static NewtonsoftJsonPatchInputFormatter GetJsonPatchInputFormatter()
{
var builder = new ServiceCollection()
.AddLogging()
.AddMvc()
.AddNewtonsoftJson()
.Services.BuildServiceProvider();
return builder
.GetRequiredService<IOptions<MvcOptions>>()
.Value
.InputFormatters
.OfType<NewtonsoftJsonPatchInputFormatter>()
.First();
}
Kode sebelumnya memerlukan Microsoft.AspNetCore.Mvc.NewtonsoftJson paket dan pernyataan berikut using :
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using System.Linq;
Newtonsoft.Json.JsonConvert.SerializeObject Gunakan metode untuk membuat serial JsonPatchDocument.
Metode permintaan HTTP PATCH
Metode PUT dan PATCH digunakan untuk memperbarui sumber daya yang ada. Perbedaannya adalah PUT menggantikan seluruh sumber daya, sementara PATCH hanya menentukan perubahan.
JSON Patch
JSON Patch adalah format untuk menentukan pembaruan yang akan diterapkan ke sumber daya. Dokumen JSON Patch memiliki array operasi. Setiap operasi mengidentifikasi jenis perubahan tertentu. Contoh perubahan tersebut termasuk menambahkan elemen array atau mengganti nilai properti.
Misalnya, dokumen JSON berikut mewakili sumber daya, dokumen Patch JSON untuk sumber daya, dan hasil penerapan operasi Patch.
Contoh sumber daya
{
"customerName": "John",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
}
]
}
Contoh patch JSON
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Dalam JSON sebelumnya:
- Properti
opmenunjukkan jenis operasi. - Properti
pathmenunjukkan elemen yang akan diperbarui. - Properti
valuemenyediakan nilai baru.
Sumber daya setelah patch
Berikut adalah sumber daya setelah menerapkan dokumen Patch JSON sebelumnya:
{
"customerName": "Barry",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
},
{
"orderName": "Order2",
"orderType": null
}
]
}
Perubahan yang dilakukan dengan menerapkan dokumen JSON Patch ke sumber daya adalah atomik. Jika ada operasi dalam daftar yang gagal, tidak ada operasi dalam daftar yang diterapkan.
Sintaks jalur
Properti jalur objek operasi memiliki garis miring antar level. Contohnya,"/address/zipCode".
Indeks berbasis nol digunakan untuk menentukan elemen array. Elemen pertama dari addresses array akan berada di /addresses/0. Untuk add ke akhir array, gunakan tanda hubung (-) daripada nomor indeks: /addresses/-.
Operations
Tabel berikut ini memperlihatkan operasi yang didukung seperti yang didefinisikan dalam spesifikasi Patch JSON:
| Operation | Notes |
|---|---|
add |
Tambahkan elemen properti atau array. Untuk properti yang ada: tetapkan nilai. |
remove |
Menghapus elemen properti atau array. |
replace |
Sama seperti remove diikuti oleh add di lokasi yang sama. |
move |
Sama seperti remove dari sumber diikuti oleh add ke tujuan menggunakan nilai dari sumber. |
copy |
Sama seperti add tujuan menggunakan nilai dari sumber. |
test |
Mengembalikan kode status keberhasilan jika nilai di path = disediakan value. |
Patch JSON di ASP.NET Core
Implementasi ASP.NET Core dari JSON Patch disediakan dalam paket NuGet Microsoft.AspNetCore.JsonPatch .
Kode metode tindakan
Dalam pengontrol API, metode tindakan untuk JSON Patch:
- Diannotasikan dengan
HttpPatchatribut . -
JsonPatchDocument<T>Menerima , biasanya dengan[FromBody]. -
ApplyToPanggilan pada dokumen patch untuk menerapkan perubahan.
Berikut contohnya:
[HttpPatch]
public IActionResult JsonPatchWithModelState(
[FromBody] JsonPatchDocument<Customer> patchDoc)
{
if (patchDoc != null)
{
var customer = CreateCustomer();
patchDoc.ApplyTo(customer, ModelState);
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
return new ObjectResult(customer);
}
else
{
return BadRequest(ModelState);
}
}
Kode dari aplikasi sampel ini berfungsi dengan model berikut Customer :
using System.Collections.Generic;
namespace JsonPatchSample.Models
{
public class Customer
{
public string CustomerName { get; set; }
public List<Order> Orders { get; set; }
}
}
namespace JsonPatchSample.Models
{
public class Order
{
public string OrderName { get; set; }
public string OrderType { get; set; }
}
}
Metode tindakan sampel:
- Membangun sebuah
Customer. - Menerapkan patch.
- Mengembalikan hasil dalam isi respons.
Dalam aplikasi nyata, kode akan mengambil data dari penyimpanan seperti database dan memperbarui database setelah menerapkan patch.
Status model
Contoh metode tindakan sebelumnya memanggil kelebihan beban ApplyTo yang mengambil status model sebagai salah satu parameternya. Dengan opsi ini, Anda bisa mendapatkan pesan kesalahan sebagai respons. Contoh berikut menunjukkan isi respons Permintaan Buruk 400 untuk test operasi:
{
"Customer": [
"The current value 'John' at path 'customerName' is not equal to the test value 'Nancy'."
]
}
Objek dinamis
Contoh metode tindakan berikut menunjukkan cara menerapkan patch ke objek dinamis:
[HttpPatch]
public IActionResult JsonPatchForDynamic([FromBody]JsonPatchDocument patch)
{
dynamic obj = new ExpandoObject();
patch.ApplyTo(obj);
return Ok(obj);
}
Operasi tambahkan
- Jika
pathmenunjuk ke elemen array: menyisipkan elemen baru sebelum elemen yang ditentukan olehpath. - Jika
pathmenunjuk ke properti: mengatur nilai properti. - Jika
pathmenunjuk ke lokasi yang tidak ada:- Jika sumber daya yang akan di-patch adalah objek dinamis: menambahkan properti.
- Jika sumber daya untuk di-patch adalah objek statis: permintaan gagal.
Contoh dokumen patch berikut mengatur nilai CustomerName dan menambahkan Order objek ke akhir Orders array.
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Operasi hapus
- Jika
pathmenunjuk ke elemen array: menghapus elemen . - Jika
pathmenunjuk ke properti:- Jika sumber daya untuk patch adalah objek dinamis: menghapus properti .
- Jika sumber daya untuk di-patch adalah objek statis:
- Jika properti nullable: mengaturnya ke null.
- Jika properti tidak dapat diubah ke null, atur ke
default<T>.
Contoh kumpulan CustomerName dokumen patch berikut ke null dan hapus Orders[0]:
[
{
"op": "remove",
"path": "/customerName"
},
{
"op": "remove",
"path": "/orders/0"
}
]
Operasi ganti
Operasi ini secara fungsional sama remove dengan diikuti oleh add.
Contoh dokumen patch berikut menetapkan nilai CustomerName dan mengganti Orders[0]dengan objek baru Order :
[
{
"op": "replace",
"path": "/customerName",
"value": "Barry"
},
{
"op": "replace",
"path": "/orders/0",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Operasi pemindahan
- Jika
pathmenunjuk ke elemen array: menyalinfromelemen ke lokasipathelemen, maka menjalankanremoveoperasi padafromelemen . - Jika
pathmenunjuk ke properti: menyalin nilaifromproperti kepathproperti, maka menjalankanremoveoperasi padafromproperti . - Jika
pathmenunjuk ke properti yang tidak ada:- Jika sumber daya untuk di-patch adalah objek statis: permintaan gagal.
- Jika sumber daya untuk patch adalah objek dinamis: menyalin
fromproperti ke lokasi yangpathditunjukkan olehremove, maka menjalankan operasi padafromproperti .
Contoh dokumen patch berikut:
- Menyalin nilai
Orders[0].OrderNamekeCustomerName. -
Orders[0].OrderNameMengatur ke null. -
Orders[1]Pindah ke sebelumOrders[0].
[
{
"op": "move",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "move",
"from": "/orders/1",
"path": "/orders/0"
}
]
Operasi salin
Operasi ini secara fungsional sama move dengan operasi tanpa langkah terakhir remove .
Contoh dokumen patch berikut:
- Menyalin nilai
Orders[0].OrderNamekeCustomerName. - Menyisipkan salinan
Orders[1]sebelumOrders[0].
[
{
"op": "copy",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "copy",
"from": "/orders/1",
"path": "/orders/0"
}
]
Operasi pengujian
Jika nilai di lokasi yang ditunjukkan oleh path berbeda dari nilai yang disediakan dalam value, permintaan gagal. Dalam hal ini, seluruh permintaan PATCH gagal bahkan jika semua operasi lain dalam dokumen patch akan berhasil.
Operasi test ini umumnya digunakan untuk mencegah pembaruan ketika ada konflik konkurensi.
Contoh dokumen patch berikut tidak berpengaruh jika nilai CustomerName awal adalah "John", karena pengujian gagal:
[
{
"op": "test",
"path": "/customerName",
"value": "Nancy"
},
{
"op": "add",
"path": "/customerName",
"value": "Barry"
}
]
Mendapatkan kode
Melihat atau mengunduh kode sampel. (Cara mengunduh).
Untuk menguji sampel, jalankan aplikasi dan kirim permintaan HTTP dengan pengaturan berikut:
- URL:
http://localhost:{port}/jsonpatch/jsonpatchwithmodelstate - Metode HTTP:
PATCH - Judul:
Content-Type: application/json-patch+json - Isi: Salin dan tempel salah satu sampel dokumen patch JSON dari folder proyek JSON .
ASP.NET Core