Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Tento článek vysvětluje, jak zpracovávat požadavky opravy JSON ve webovém rozhraní API ASP.NET Core.
Podpora oprav JSON ve webovém rozhraní API ASP.NET Core je založená na System.Text.Json serializaci a vyžaduje Microsoft.AspNetCore.JsonPatch.SystemTextJson balíček NuGet.
Co je standard JSON Patch?
Standard opravy JSON:
Je standardní formát pro popis změn, které se mají použít u dokumentu JSON.
Je definován v RFC 6902 a je široce používán v rozhraníCH RESTful API k provádění částečných aktualizací prostředků JSON.
Popisuje posloupnost operací, které upravují dokument JSON, například:
addremovereplacemovecopytest
Ve webových aplikacích se JSON Patch běžně používá v operaci PATCH k provádění částečných aktualizací prostředků. Místo odeslání celého prostředku pro aktualizaci můžou klienti odeslat dokument JSON Patch obsahující pouze změny. Patchování snižuje velikost přenášených dat a zlepšuje efektivitu.
Přehled standardu JSON Patch najdete na jsonpatch.com.
Podpora oprav JSON ve webovém rozhraní API ASP.NET Core
Podpora JSON Patch ve webovém API ASP.NET Core je založena na serializaci pomocí System.Text.Json, počínaje verzí .NET 10. Implementuje Microsoft.AspNetCore.JsonPatch na základě serializace System.Text.Json. Tato funkce:
-
Microsoft.AspNetCore.JsonPatch.SystemTextJsonVyžaduje balíček NuGet. - V souladu s moderními postupy .NET využívá knihovnu System.Text.Json , která je optimalizovaná pro .NET.
- Poskytuje lepší výkon a snížené využití paměti v porovnání s implementací založenou na starší
Newtonsoft.Jsonverzi. Další informace o staršíNewtonsoft.Jsonimplementaci naleznete v verzi tohoto článku pro .NET 9.
Note
Implementace Microsoft.AspNetCore.JsonPatch založená na System.Text.Json serializaci není náhradou za starší implementaci založenou na Newtonsoft.Json. Nepodporuje dynamické typy, například ExpandoObject.
Important
Standard JSON Patch má vlastní bezpečnostní rizika. Vzhledem k tomu, že tato rizika jsou součástí standardu JSON Patch, implementace ASP.NET Core se nepokouší zmírnit vlastní rizika zabezpečení. Je zodpovědností vývojáře, aby se zajistilo, že dokument Opravy JSON je bezpečný pro cílový objekt. Další informace najdete v části Omezení rizik zabezpečení .
Povolit podporu JSON Patch s využitím System.Text.Json
Chcete-li povolit podporu pro JSON Patch, nainstalujte balíček NuGet System.Text.JsonMicrosoft.AspNetCore.JsonPatch.SystemTextJson.
dotnet add package Microsoft.AspNetCore.JsonPatch.SystemTextJson
Tento balíček poskytuje JsonPatchDocument<TModel> třídu představující dokument JSON Patch pro objekty typu TModel a vlastní logiky pro serializaci a deserializaci dokumentů JSON Patch pomocí System.Text.Json. Klíčovou metodou JsonPatchDocument<TModel> třídy je ApplyTo(Object), která aplikuje operace opravy na cílový objekt typu TModel.
Minimální koncový bod PATCH rozhraní API, který používá opravu JSON
V minimálním rozhraní API koncový bod PATCH pro opravu JSON:
- Slouží
MapPatchk definování trasy. - Přijímá parametr JsonPatchDocument<TModel>.
- Zavolá ApplyTo(Object) na dokumentu záplaty, aby se změny použily.
Příklad endpointu PATCH rozhraní Minimal API
group.MapPatch("/{id}", async Task<Results<Ok<Customer>,ValidationProblem,NotFound<ProblemDetails>>> (AppDb db, string id,
JsonPatchDocument<Customer> patchDoc) =>
{
var customer = await db.Customers.Include(c => c.Orders).FirstOrDefaultAsync(c => c.Id == id);
if (customer is null)
{
return TypedResults.NotFound<ProblemDetails>(new ());
}
if (patchDoc != null)
{
Dictionary<string, string[]>? errors = null;
patchDoc.ApplyTo(customer, 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)
{
return TypedResults.ValidationProblem(errors);
}
// Only save if there are no errors
await db.SaveChangesAsync();
}
return TypedResults.Ok(customer);
})
.Accepts<JsonPatchDocument<Customer>>("application/json-patch+json");
Tento kód z ukázkové aplikace funguje s následujícími Customer modely a Order modely:
using System.ComponentModel.DataAnnotations;
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();
}
}
Klíčové kroky ukázkového koncového bodu PATCH:
-
Načtení zákazníka:
- Koncový bod načte z databáze
AppDbobjektCustomerna základě zadanéhoid. - Pokud nebyl nalezen žádný
Customerobjekt, vrátí404 Not Foundodpověď prostřednictvímTypedResults.NotFound().
- Koncový bod načte z databáze
-
Použít opravu JSON:
- Metoda ApplyTo(Object) aplikuje operace JSON Patch z
patchDocna načtený objektCustomer. - Pokud během aplikace oprav dojde k chybám, jako jsou neplatné operace nebo konflikty, delegát zpracování chyb je zachytí. Tento delegát shromažďuje chybové zprávy do slovníku s klíčem typu ovlivněného objektu.
- Metoda ApplyTo(Object) aplikuje operace JSON Patch z
-
Vrátit chyby validace:
- Pokud delegát zpracování chyb zaznamenává jakékoli chyby během aplikace opravy, koncový bod vrátí
ValidationProblemodpověď obsahující podrobnosti o chybě prostřednictvímTypedResults.ValidationProblem(errors).
- Pokud delegát zpracování chyb zaznamenává jakékoli chyby během aplikace opravy, koncový bod vrátí
-
Uložte a vraťte aktualizovaného zákazníka:
- Pokud se oprava úspěšně použije bez chyb, změny se uloží do databáze a koncový bod vrátí aktualizovaný
Customerobjekt prostřednictvímTypedResults.Ok(customer).
- Pokud se oprava úspěšně použije bez chyb, změny se uloží do databáze a koncový bod vrátí aktualizovaný
Příklad odpovědi na chybu
Následující příklad ukazuje tělo odpovědi problému s validací pro operaci JSON Patch, pokud je zadaná cesta neplatná:
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"Customer": [
"The target location specified by path segment 'foobar' was not found."
]
}
}
Použití dokumentu opravy JSON u objektu
Následující příklady ukazují, jak použít metodu ApplyTo(Object) k použití dokumentu JSON Patch na objekt.
Příklad: Aplikujte JsonPatchDocument<TModel> na objekt
Následující příklad ukazuje:
- Operace
add,replacearemove. - Operace s vnořenými vlastnostmi
- Přidání nové položky do pole
- Použití převaděče výčtu řetězců JSON v dokumentu opravy 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));
Předchozí příklad vede k následujícímu výstupu aktualizovaného objektu:
{
"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"
}
]
}
Metoda ApplyTo(Object) obecně dodržuje konvence a možnosti System.Text.Json zpracování JsonPatchDocument<TModel>, včetně chování řízeného následujícími možnostmi:
- JsonNumberHandling: Určuje, zda jsou číselné vlastnosti načteny z řetězců.
- PropertyNameCaseInsensitive: Zda názvy vlastností rozlišují velká a malá písmena.
Hlavní rozdíly mezi System.Text.Json a novou JsonPatchDocument<TModel> implementací:
- Typ modulu runtime cílového objektu, nikoli deklarovaný typ, určuje, které vlastnosti ApplyTo(Object) se opravují.
- System.Text.Json deserializace spoléhá na deklarovaný typ pro identifikaci způsobilých vlastností.
Příklad: Použití jsonPatchDocument se zpracováním chyb
Při použití dokumentu opravy JSON může dojít k různým chybám. Například cílový objekt nemusí mít zadanou vlastnost nebo zadaná hodnota může být nekompatibilní s typem vlastnosti.
JSON Patch podporuje test operaci, která kontroluje, jestli se zadaná hodnota rovná cílové vlastnosti. Pokud ne, vrátí chybu.
Následující příklad ukazuje, jak tyto chyby řádně zpracovat.
Important
Objekt předaný ApplyTo(Object) metodě je změněn na místě. Volající zodpovídá za zahození změn v případě selhání jakékoli operace.
// 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));
Výsledkem předchozího příkladu je následující výstup:
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": []
}
Zmírnění rizik zabezpečení
Při používání Microsoft.AspNetCore.JsonPatch.SystemTextJson balíčku je důležité pochopit a zmírnit potenciální rizika zabezpečení. Následující části popisují identifikovaná bezpečnostní rizika spojená s opravou JSON a poskytují doporučená omezení rizik pro zajištění zabezpečeného používání balíčku.
Important
Nejedná se o vyčerpávající seznam hrozeb. Vývojářiaplikacích aplikací musí provádět vlastní kontroly modelu hrozeb, aby mohli podle potřeby určit komplexní seznam specifických pro konkrétní aplikaci a podle potřeby přijít s vhodnými omezeními rizik. Například aplikace, které zpřístupňují kolekce operacím oprav, by měly zvážit potenciál útoků na algoritmickou složitost, pokud tyto operace vloží nebo odeberou prvky na začátku kolekce.
Aby vývojáři mohli minimalizovat rizika zabezpečení při integraci funkcí oprav JSON do svých aplikací, měli by:
- Spusťte komplexní modely hrozeb pro své vlastní aplikace.
- Vyřešte zjištěné hrozby.
- Postupujte podle doporučených omezení rizik v následujících částech.
Odepření služby (DoS) prostřednictvím amplifikace paměti
-
Scénář: Škodlivý klient odešle operaci, která několikrát duplikuje
copygrafy velkých objektů, což vede k nadměrné spotřebě paměti. - Dopad: Možné podmínkyOf-Memory (OOM), které mohou způsobit přerušení služeb.
-
Mitigation:
- Před voláním ApplyTo(Object)ověřte příchozí dokumenty JSON Patch pro velikost a strukturu .
- Ověření musí být specifické pro aplikaci, ale ukázkové ověření může vypadat nějak takto:
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();
}
}
Narušení obchodní logiky
- Scénář: Operace oprav můžou manipulovat s poli s implicitními invarianty (například s interními příznaky, ID nebo vypočítanými poli), porušením obchodních omezení.
- Dopad: Problémy s integritou dat a nezamýšlené chování aplikací
-
Mitigation:
- Použijte objekty POCOs (Plain Old CLR) s explicitně definovanými vlastnostmi, které jsou bezpečné k úpravě.
- Vyhněte se zveřejnění citlivých nebo kritických vlastností zabezpečení v cílovém objektu.
- Pokud se objekt POCO nepoužívá, ověřte po použití operací opravený objekt, abyste zajistili, že nedojde k porušení obchodních pravidel a invariantů.
- Použijte objekty POCOs (Plain Old CLR) s explicitně definovanými vlastnostmi, které jsou bezpečné k úpravě.
Autentizace a autorizace
- Scénář: Neověřené nebo neautorizované klienty odesílají škodlivé požadavky na opravu JSON.
- Dopad: Neoprávněný přístup k úpravě citlivých dat nebo narušení chování aplikace
-
Mitigation:
- Chraňte koncové body, které přijímají požadavky JSON Patch, pomocí správných mechanismů ověřování a autorizace.
- Omezte přístup k důvěryhodným klientům nebo uživatelům s příslušnými oprávněními.
Získání kódu
Zobrazení nebo stažení vzorového kódu (postup stahování).
Ukázku otestujete spuštěním aplikace a odesláním požadavků HTTP pomocí zahrnutého .http souboru.
Dodatečné zdroje
Tento článek vysvětluje, jak zpracovávat požadavky opravy JSON ve webovém rozhraní API ASP.NET Core.
Important
Standard JSON Patch má vlastní bezpečnostní rizika. Tato implementace se nepokouší tyto základní bezpečnostní rizika zmírnit. Je zodpovědností vývojáře, aby se zajistilo, že dokument Opravy JSON je bezpečný pro cílový objekt. Další informace najdete v části Omezení rizik zabezpečení .
Instalace balíčku
Podpora JSON Patch ve webovém rozhraní API ASP.NET Core je založená na Newtonsoft.Json a vyžaduje balíček NuGet Microsoft.AspNetCore.Mvc.NewtonsoftJson.
Chcete-li povolit podporu JSON Patch:
Microsoft.AspNetCore.Mvc.NewtonsoftJsonNainstalujte balíček NuGet.Zavolejte AddNewtonsoftJson. Například:
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers() .AddNewtonsoftJson(); var app = builder.Build(); app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();
AddNewtonsoftJson nahrazuje výchozí System.Text.Jsonvstupní a výstupní formátovací moduly založené na formátu všech souborů JSON. Tato metoda rozšíření je kompatibilní s následujícími metodami registrace služby MVC:
JsonPatch vyžaduje nastavení hlavičky Content-Type na application/json-patch+json.
Přidat podporu pro JSON Patch při použití System.Text.Json
Vstupní formátovač založený na System.Text.Json nepodporuje JSON Patch. Chcete-li přidat podporu pro JSON Patch pomocí Newtonsoft.Json, přičemž ostatní vstupní a výstupní formátovače zůstanou beze změny:
Microsoft.AspNetCore.Mvc.NewtonsoftJsonNainstalujte balíček NuGet.Aktualizace
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(); } }
Předchozí kód vytvoří instanci NewtonsoftJsonPatchInputFormatter a vloží ji jako první položku v kolekci MvcOptions.InputFormatters . Toto pořadí registrace zajišťuje, že:
-
NewtonsoftJsonPatchInputFormatterzpracovává požadavky JSON Patch. - Stávající vstupní procesory a formátovače založené na
System.Text.Jsonzpracovávají všechny ostatní požadavky a odpovědi ve formátu JSON.
Použijte metodu Newtonsoft.Json.JsonConvert.SerializeObject k serializaci JsonPatchDocument.
Metoda požadavku HTTP PATCH
Metody PUT a PATCH slouží k aktualizaci existujícího prostředku. Rozdíl mezi nimi spočívá v tom, že PUT nahrazuje celý prostředek, zatímco patch určuje pouze změny.
JSON Patch
JSON Patch je formát pro určení aktualizací, které se mají použít na prostředek. Dokument opravy JSON obsahuje pole operací. Každá operace identifikuje konkrétní typ změny. Mezi příklady takových změn patří přidání prvku pole nebo nahrazení hodnoty vlastnosti.
Například následující dokumenty JSON představují prostředek, dokument JSON Patch pro daný prostředek a výsledek použití operací JSON Patch.
Příklad zdroje
{
"customerName": "John",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
}
]
}
Příklad opravy JSON
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
V předchozím fragmentu kódu JSON:
- Vlastnost
opoznačuje typ operace. - Vlastnost
pathoznačuje prvek, který se má aktualizovat. - Vlastnost
valueposkytuje novou hodnotu.
Zdroj po aplikaci záplaty
Zde je zdroj po použití předchozího dokumentu JSON Patch:
{
"customerName": "Barry",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
},
{
"orderName": "Order2",
"orderType": null
}
]
}
Změny provedené aplikací dokumentu JSON Patch na prostředku jsou atomické. Pokud jakákoli operace v seznamu selže, nepoužije se žádná operace v seznamu.
Syntaxe cesty
Vlastnost path objektu operace obsahuje mezi úrovněmi lomítka. Například "/address/zipCode".
Indexy založené na nule slouží k určení prvků pole. První prvek pole addresses by byl na /addresses/0. Na konec pole add použijte místo čísla indexu pomlčku (-): /addresses/-.
Operations
Následující tabulka uvádí podporované operace definované ve specifikaci opravy JSON:
| Operation | Notes |
|---|---|
add |
Přidejte vlastnost nebo prvek pole. Pro existující vlastnost: nastavte hodnotu. |
remove |
Odeberte vlastnost nebo prvek pole. |
replace |
Stejné jako remove následované add na stejném místě. |
move |
Stejné jako remove ze zdroje, následované add do cíle s použitím hodnoty ze zdroje. |
copy |
Stejné jako add cíl s použitím hodnoty ze zdroje. |
test |
Vrátí stavový kód úspěchu, pokud hodnota na path = zadaná hodnota value. |
Oprava JSON v ASP.NET Core
Implementace JSON Patch pro ASP.NET Core je k dispozici v balíčku NuGet Microsoft.AspNetCore.JsonPatch.
Kód metody akce
V kontroleru rozhraní API metoda akce pro opravu JSON:
- Je opatřen atributem
HttpPatch. - Přijímá JsonPatchDocument<TModel>, obvykle s
[FromBody]. - Zavolá ApplyTo(Object) na dokumentu záplaty, aby se změny použily.
Tady je příklad:
[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);
}
}
Tento kód z ukázkové aplikace funguje s následujícím Customer modelem:
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; }
}
Ukázková metoda akce:
- Vytvoří objekt
Customer. - Použije opravu.
- Vrátí výsledek v textu odpovědi.
V reálné aplikaci by kód načetl data z úložiště, jako je databáze, a po instalaci opravy databázi aktualizoval.
Stav modelu
Předchozí příklad metody akce volá jednu z přetížených verzí metody ApplyTo, která přijímá stav modelu jako jeden ze svých parametrů. Pomocí této možnosti můžete v odpovědích zobrazit chybové zprávy. Následující příklad ukazuje tělo odpovědi 400 Bad Request pro operaci test:
{
"Customer": [
"The current value 'John' at path 'customerName' != test value 'Nancy'."
]
}
Dynamické objekty
Následující příklad metody akce ukazuje, jak použít opravu na dynamický objekt:
[HttpPatch]
public IActionResult JsonPatchForDynamic([FromBody]JsonPatchDocument patch)
{
dynamic obj = new ExpandoObject();
patch.ApplyTo(obj);
return Ok(obj);
}
Operace přidání
- Pokud
pathodkazuje na prvek pole: vloží nový prvek před prvek určenýpath. - Pokud
pathodkazuje na vlastnost: nastaví hodnotu vlastnosti. - Pokud
pathodkazuje na neexistující umístění:- Pokud je prostředek k opravě dynamickým objektem: přidá vlastnost.
- Pokud je prostředek, který se má opravit, statický objekt: požadavek selže.
Následující ukázkový dokument opravy nastaví hodnotu CustomerName a přidá Order objekt na konec Orders pole.
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Operace odebrání
- Pokud
pathodkazuje na prvek pole: odebere prvek. - Pokud
pathodkazuje na vlastnost:- Pokud je objekt, na který se aplikuje oprava, dynamickým objektem: vlastnost se odebere.
- Pokud je prostředek k opravě statický objekt:
- Pokud je vlastnost nullable: nastaví ji na hodnotu null.
- Pokud vlastnost není nullable, nastaví ji na
default<T>.
Následující ukázkový dokument opravy nastaví CustomerName hodnotu null a odstraní Orders[0]:
[
{
"op": "remove",
"path": "/customerName"
},
{
"op": "remove",
"path": "/orders/0"
}
]
Operace nahrazení
Tato operace je z funkčního hlediska stejná jako remove, po níž následuje add.
Následující ukázkový dokument opravy nastaví hodnotu CustomerName a nahradí Orders[0]novým Order objektem:
[
{
"op": "replace",
"path": "/customerName",
"value": "Barry"
},
{
"op": "replace",
"path": "/orders/0",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Operace přesunutí
- Pokud
pathodkazuje na prvek pole: zkopíruje prvekfromna umístění prvkupatha poté provede operaciremoves prvkemfrom. - Pokud
pathodkazuje na vlastnost: zkopíruje hodnotu vlastnostifromdo vlastnostipath, poté provede operaciremoves vlastnostífrom. - Pokud
pathodkazuje na neexistující vlastnost:- Pokud je prostředek, který se má opravit, statický objekt: požadavek selže.
- Pokud je prostředek, který se má opravit, dynamický objekt: zkopíruje vlastnost
fromdo umístění určeného pomocípatha poté provede operaciremoveu vlastnostifrom.
Následující ukázkový dokument opravy:
- Zkopíruje hodnotu
Orders[0].OrderNamedoCustomerName. - Nastaví
Orders[0].OrderNamena hodnotu null. - Přesune
Orders[1]předOrders[0].
[
{
"op": "move",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "move",
"from": "/orders/1",
"path": "/orders/0"
}
]
Operace kopírování
Tato operace je funkčně stejná jako move operace bez posledního remove kroku.
Následující ukázkový dokument opravy:
- Zkopíruje hodnotu
Orders[0].OrderNamedoCustomerName. - Vloží kopii
Orders[1]předOrders[0].
[
{
"op": "copy",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "copy",
"from": "/orders/1",
"path": "/orders/0"
}
]
Testovací operace
Pokud se hodnota v umístění označeném path hodnotou liší od hodnoty zadané v value, požadavek selže. V takovém případě celý požadavek PATCH selže i v případě, že by všechny ostatní operace v dokumentu opravy jinak proběhly úspěšně.
Operace test se běžně používá k zabránění aktualizaci, když dojde ke konfliktu souběžnosti.
Následující ukázkový dokument opravy nemá žádný vliv, pokud je počáteční hodnota CustomerName "John", protože test selže:
[
{
"op": "test",
"path": "/customerName",
"value": "Nancy"
},
{
"op": "add",
"path": "/customerName",
"value": "Barry"
}
]
Získání kódu
Zobrazení nebo stažení vzorového kódu (postup stahování).
Ukázku otestujete spuštěním aplikace a odesláním požadavků HTTP s následujícím nastavením:
- Adresa URL:
http://localhost:{port}/jsonpatch/jsonpatchwithmodelstate - Metoda HTTP:
PATCH - Záhlaví:
Content-Type: application/json-patch+json - Text: Zkopírujte a vložte jednu z ukázek dokumentu opravy JSON ze složky projektu JSON .
Zmírnění rizik zabezpečení
Při použití balíčku Microsoft.AspNetCore.JsonPatch s implementací založenou na Newtonsoft.Json je důležité pochopit a zmírnit potenciální bezpečnostní rizika. Následující části popisují identifikovaná bezpečnostní rizika spojená s opravou JSON a poskytují doporučená omezení rizik pro zajištění zabezpečeného používání balíčku.
Important
Nejedná se o vyčerpávající seznam hrozeb. Vývojářiaplikacích aplikací musí provádět vlastní kontroly modelu hrozeb, aby mohli podle potřeby určit komplexní seznam specifických pro konkrétní aplikaci a podle potřeby přijít s vhodnými omezeními rizik. Například aplikace, které zpřístupňují kolekce operacím oprav, by měly zvážit potenciál útoků na algoritmickou složitost, pokud tyto operace vloží nebo odeberou prvky na začátku kolekce.
Spuštěním komplexních modelů hrozeb pro své vlastní aplikace a řešení identifikovaných hrozeb a dodržováním následujících doporučených omezení rizik můžou uživatelé těchto balíčků integrovat funkce oprav JSON do svých aplikací a současně minimalizovat rizika zabezpečení.
Odepření služby (DoS) prostřednictvím amplifikace paměti
-
Scénář: Škodlivý klient odešle operaci, která několikrát duplikuje
copygrafy velkých objektů, což vede k nadměrné spotřebě paměti. - Dopad: Možné podmínkyOf-Memory (OOM), které mohou způsobit přerušení služeb.
-
Mitigation:
- Před voláním
ApplyToověřte příchozí dokumenty JSON Patch pro velikost a strukturu . - Ověření musí být specifické pro aplikaci, ale ukázkové ověření může vypadat nějak takto:
- Před voláním
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();
}
}
Podvracení obchodní logiky
- Scénář: Operace oprav můžou manipulovat s poli s implicitními invarianty (například s interními příznaky, ID nebo vypočítanými poli), porušením obchodních omezení.
- Dopad: Problémy s integritou dat a nezamýšlené chování aplikací
-
Mitigation:
- Použijte objekty POCO s explicitně definovanými vlastnostmi, které jsou bezpečné k úpravě.
- Vyhněte se zveřejnění citlivých nebo kritických vlastností zabezpečení v cílovém objektu.
- Pokud se nepoužívá žádný objekt POCO, validujte objekt po použití operací, abyste zajistili, že nebudou porušena obchodní pravidla a invarianty.
Autentizace a autorizace
- Scénář: Neověřené nebo neautorizované klienty odesílají škodlivé požadavky na opravu JSON.
- Dopad: Neoprávněný přístup k úpravě citlivých dat nebo narušení chování aplikace
-
Mitigation:
- Ochrana koncových bodů, které přijímají žádosti o opravu JSON, pomocí správných mechanismů ověřování a autorizace
- Omezte přístup k důvěryhodným klientům nebo uživatelům s příslušnými oprávněními.
Dodatečné zdroje
Tento článek vysvětluje, jak zpracovávat požadavky opravy JSON ve webovém rozhraní API ASP.NET Core.
Important
Standard JSON Patch má vlastní bezpečnostní rizika. Vzhledem k tomu, že tato rizika jsou součástí standardu JSON Patch, tato implementace se nepokouší zmírnit vlastní rizika zabezpečení. Je zodpovědností vývojáře, aby se zajistilo, že dokument Opravy JSON je bezpečný pro cílový objekt. Další informace najdete v části Omezení rizik zabezpečení .
Instalace balíčku
Pokud chcete ve své aplikaci povolit podporu oprav JSON, proveďte následující kroky:
Microsoft.AspNetCore.Mvc.NewtonsoftJsonNainstalujte balíček NuGet.Aktualizujte metodu
Startup.ConfigureServicesprojektu tak, aby volala AddNewtonsoftJson. Například:services .AddControllersWithViews() .AddNewtonsoftJson();
AddNewtonsoftJson je kompatibilní s metodami registrace služby MVC:
Oprava JSON, AddNewtonsoftJson a System.Text.Json
AddNewtonsoftJson nahrazuje vstupní a výstupní formátovače založené na System.Text.Json, které se používají k formátování veškerého obsahu JSON. Pokud chcete přidat podporu pro opravu JSON pomocí Newtonsoft.Json, zatímco ostatní formátovací moduly zůstanou beze změny, aktualizujte metodu Startup.ConfigureServices projektu následujícím způsobem:
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();
}
Předchozí kód vyžaduje Microsoft.AspNetCore.Mvc.NewtonsoftJson balíček a následující using příkazy:
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;
Použijte metodu Newtonsoft.Json.JsonConvert.SerializeObject k serializaci JsonPatchDocument.
Metoda požadavku HTTP PATCH
Metody PUT a PATCH slouží k aktualizaci existujícího prostředku. Rozdíl mezi nimi spočívá v tom, že PUT nahrazuje celý prostředek, zatímco patch určuje pouze změny.
JSON Patch
JSON Patch je formát pro určení aktualizací, které se mají použít na prostředek. Dokument opravy JSON obsahuje pole operací. Každá operace identifikuje konkrétní typ změny. Mezi příklady takových změn patří přidání prvku pole nebo nahrazení hodnoty vlastnosti.
Například následující dokumenty JSON představují prostředek, dokument JSON Patch pro daný prostředek a výsledek použití operací JSON Patch.
Příklad zdroje
{
"customerName": "John",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
}
]
}
Příklad opravy JSON
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
V předchozím fragmentu kódu JSON:
- Vlastnost
opoznačuje typ operace. - Vlastnost
pathoznačuje prvek, který se má aktualizovat. - Vlastnost
valueposkytuje novou hodnotu.
Zdroj po aplikaci záplaty
Zde je zdroj po použití předchozího dokumentu JSON Patch:
{
"customerName": "Barry",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
},
{
"orderName": "Order2",
"orderType": null
}
]
}
Změny provedené aplikací dokumentu JSON Patch na prostředku jsou atomické. Pokud jakákoli operace v seznamu selže, nepoužije se žádná operace v seznamu.
Syntaxe cesty
Vlastnost path objektu operace obsahuje mezi úrovněmi lomítka. Například "/address/zipCode".
Indexy založené na nule slouží k určení prvků pole. První prvek pole addresses by byl na /addresses/0. Na konec pole add použijte místo čísla indexu pomlčku (-): /addresses/-.
Operations
Následující tabulka uvádí podporované operace definované ve specifikaci opravy JSON:
| Operation | Notes |
|---|---|
add |
Přidejte vlastnost nebo prvek pole. Pro existující vlastnost: nastavte hodnotu. |
remove |
Odeberte vlastnost nebo prvek pole. |
replace |
Stejné jako remove následované add na stejném místě. |
move |
Stejné jako remove ze zdroje, následované add do cíle s použitím hodnoty ze zdroje. |
copy |
Stejné jako add cíl s použitím hodnoty ze zdroje. |
test |
Vrátí stavový kód úspěchu, pokud hodnota na path = zadaná hodnota value. |
Oprava JSON v ASP.NET Core
Implementace JSON Patch pro ASP.NET Core je k dispozici v balíčku NuGet Microsoft.AspNetCore.JsonPatch.
Kód metody akce
V kontroleru rozhraní API metoda akce pro opravu JSON:
- Je opatřen atributem
HttpPatch. - Přijímá
JsonPatchDocument<T>, obvykle s[FromBody]. - Zavolá
ApplyTona dokumentu záplaty, aby se změny použily.
Tady je příklad:
[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);
}
}
Tento kód z ukázkové aplikace funguje s následujícím Customer modelem:
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; }
}
}
Ukázková metoda akce:
- Vytvoří objekt
Customer. - Použije opravu.
- Vrátí výsledek v textu odpovědi.
V reálné aplikaci by kód načetl data z úložiště, jako je databáze, a po instalaci opravy databázi aktualizoval.
Stav modelu
Předchozí příklad metody akce volá jednu z přetížených verzí metody ApplyTo, která přijímá stav modelu jako jeden ze svých parametrů. Pomocí této možnosti můžete v odpovědích zobrazit chybové zprávy. Následující příklad ukazuje tělo odpovědi 400 Bad Request pro operaci test:
{
"Customer": [
"The current value 'John' at path 'customerName' is not equal to the test value 'Nancy'."
]
}
Dynamické objekty
Následující příklad metody akce ukazuje, jak použít opravu na dynamický objekt:
[HttpPatch]
public IActionResult JsonPatchForDynamic([FromBody]JsonPatchDocument patch)
{
dynamic obj = new ExpandoObject();
patch.ApplyTo(obj);
return Ok(obj);
}
Operace přidání
- Pokud
pathodkazuje na prvek pole: vloží nový prvek před prvek určenýpath. - Pokud
pathodkazuje na vlastnost: nastaví hodnotu vlastnosti. - Pokud
pathodkazuje na neexistující umístění:- Pokud je prostředek k opravě dynamickým objektem: přidá vlastnost.
- Pokud je prostředek, který se má opravit, statický objekt: požadavek selže.
Následující ukázkový dokument opravy nastaví hodnotu CustomerName a přidá Order objekt na konec Orders pole.
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Operace odebrání
- Pokud
pathodkazuje na prvek pole: odebere prvek. - Pokud
pathodkazuje na vlastnost:- Pokud je objekt, na který se aplikuje oprava, dynamickým objektem: vlastnost se odebere.
- Pokud je prostředek k opravě statický objekt:
- Pokud je vlastnost nullable: nastaví ji na hodnotu null.
- Pokud vlastnost není nullable, nastaví ji na
default<T>.
Následující ukázkový dokument opravy nastaví CustomerName hodnotu null a odstraní Orders[0]:
[
{
"op": "remove",
"path": "/customerName"
},
{
"op": "remove",
"path": "/orders/0"
}
]
Operace nahrazení
Tato operace je z funkčního hlediska stejná jako remove, po níž následuje add.
Následující ukázkový dokument opravy nastaví hodnotu CustomerName a nahradí Orders[0]novým Order objektem:
[
{
"op": "replace",
"path": "/customerName",
"value": "Barry"
},
{
"op": "replace",
"path": "/orders/0",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Operace přesunutí
- Pokud
pathodkazuje na prvek pole: zkopíruje prvekfromna umístění prvkupatha poté provede operaciremoves prvkemfrom. - Pokud
pathodkazuje na vlastnost: zkopíruje hodnotu vlastnostifromdo vlastnostipath, poté provede operaciremoves vlastnostífrom. - Pokud
pathodkazuje na neexistující vlastnost:- Pokud je prostředek, který se má opravit, statický objekt: požadavek selže.
- Pokud je prostředek, který se má opravit, dynamický objekt: zkopíruje vlastnost
fromdo umístění určeného pomocípatha poté provede operaciremoveu vlastnostifrom.
Následující ukázkový dokument opravy:
- Zkopíruje hodnotu
Orders[0].OrderNamedoCustomerName. - Nastaví
Orders[0].OrderNamena hodnotu null. - Přesune
Orders[1]předOrders[0].
[
{
"op": "move",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "move",
"from": "/orders/1",
"path": "/orders/0"
}
]
Operace kopírování
Tato operace je funkčně stejná jako move operace bez posledního remove kroku.
Následující ukázkový dokument opravy:
- Zkopíruje hodnotu
Orders[0].OrderNamedoCustomerName. - Vloží kopii
Orders[1]předOrders[0].
[
{
"op": "copy",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "copy",
"from": "/orders/1",
"path": "/orders/0"
}
]
Testovací operace
Pokud se hodnota v umístění označeném path hodnotou liší od hodnoty zadané v value, požadavek selže. V takovém případě celý požadavek PATCH selže i v případě, že by všechny ostatní operace v dokumentu opravy jinak proběhly úspěšně.
Operace test se běžně používá k zabránění aktualizaci, když dojde ke konfliktu souběžnosti.
Následující ukázkový dokument opravy nemá žádný vliv, pokud je počáteční hodnota CustomerName "John", protože test selže:
[
{
"op": "test",
"path": "/customerName",
"value": "Nancy"
},
{
"op": "add",
"path": "/customerName",
"value": "Barry"
}
]
Získání kódu
Zobrazení nebo stažení vzorového kódu (postup stahování).
Ukázku otestujete spuštěním aplikace a odesláním požadavků HTTP s následujícím nastavením:
- Adresa URL:
http://localhost:{port}/jsonpatch/jsonpatchwithmodelstate - Metoda HTTP:
PATCH - Záhlaví:
Content-Type: application/json-patch+json - Text: Zkopírujte a vložte jednu z ukázek dokumentu opravy JSON ze složky projektu JSON .