Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
W tym artykule wyjaśniono, jak obsługiwać żądania poprawek JSON w internetowym interfejsie API platformy ASP.NET Core.
Obsługa poprawek JSON w internetowym interfejsie API platformy ASP.NET Core jest oparta na System.Text.Json serializacji i wymaga Microsoft.AspNetCore.JsonPatch.SystemTextJson
pakietu NuGet.
Co to jest standard poprawki JSON?
Standard poprawki JSON:
To standardowy format opisujący zmiany, które mają być stosowane do dokumentu JSON.
Jest definiowany w dokumencie RFC 6902 i jest powszechnie używany w interfejsach API RESTful do wykonywania częściowych aktualizacji zasobów JSON.
Opisuje sekwencję operacji modyfikujących dokument JSON, na przykład:
add
remove
replace
move
copy
test
W aplikacjach internetowych poprawka JSON jest często używana w operacji PATCH do wykonywania częściowych aktualizacji zasobu. Zamiast wysyłać cały zasób aktualizacji, klienci mogą wysyłać dokument poprawki JSON zawierający tylko zmiany. Stosowanie poprawek zmniejsza rozmiar ładunku i zwiększa wydajność.
Aby zapoznać się z omówieniem standardu JSON Patch, zobacz jsonpatch.com.
Obsługa poprawek JSON w internetowym interfejsie API platformy ASP.NET Core
Obsługa poprawek JSON w webowym interfejsie API platformy ASP.NET Core jest oparta na System.Text.Json serializacji, począwszy od wersji .NET 10, implementacji Microsoft.AspNetCore.JsonPatch w oparciu o serializację System.Text.Json. Ta funkcja:
-
Microsoft.AspNetCore.JsonPatch.SystemTextJson
Wymaga pakietu NuGet. - Jest zgodny z nowoczesnymi rozwiązaniami platformy .NET dzięki wykorzystaniu System.Text.Json biblioteki zoptymalizowanej pod kątem platformy .NET.
- Zapewnia lepszą wydajność i mniejsze użycie pamięci w porównaniu ze starszą implementacją opartą na
Newtonsoft.Json
. Aby uzyskać więcej informacji na temat starszej implementacji opartej naNewtonsoft.Json
, zobacz wersję artykułu z .NET 9.
Uwaga / Notatka
Implementacja Microsoft.AspNetCore.JsonPatch oparta na System.Text.Json serializacji nie jest zamiennikiem dla starszej implementacji opartej na Newtonsoft.Json
. Nie obsługuje typów dynamicznych, na przykład ExpandoObject.
Ważne
Standard poprawki JSON ma nieodłączne zagrożenia bezpieczeństwa. Ponieważ te zagrożenia są związane ze standardem poprawki JSON, implementacja ASP.NET Core nie próbuje ograniczyć ryzyka związanego z zabezpieczeniami. Jest to odpowiedzialność dewelopera za zapewnienie, że dokument poprawki JSON jest bezpieczny do zastosowania do obiektu docelowego. Aby uzyskać więcej informacji, zobacz sekcję Ograniczanie ryzyka zabezpieczeń .
Włączanie obsługi poprawek JSON za pomocą polecenia System.Text.Json
Aby włączyć obsługę JSON Patch za pomocą System.Text.Json, zainstaluj pakiet NuGet Microsoft.AspNetCore.JsonPatch.SystemTextJson
.
dotnet add package Microsoft.AspNetCore.JsonPatch.SystemTextJson --prerelease
Ten pakiet zawiera klasę reprezentującą JsonPatchDocument<TModel> dokument poprawki JSON dla obiektów typu T
oraz dedykowaną logikę do serializacji i deserializacji dokumentów poprawek JSON z użyciem System.Text.Json. Kluczową metodą JsonPatchDocument<TModel> klasy jest ApplyTo(Object), która stosuje operacje poprawek do obiektu docelowego typu T
.
Kod metody akcji stosujący poprawkę JSON
W kontrolerze interfejsu API metoda akcji dla poprawki JSON:
- Jest adnotacją z atrybutem HttpPatchAttribute .
- Akceptuje element JsonPatchDocument<TModel>, zazwyczaj z elementem FromBodyAttribute.
- Wywołuje ApplyTo(Object) dokument poprawki, aby zastosować zmiany.
Przykładowa metoda akcji kontrolera:
[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);
}
Kod z tej przykładowej aplikacji działa z następującymi modelami: Customer
i 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();
}
}
Kluczowe kroki metody przykładowej akcji:
-
Pobierz klienta:
- Metoda pobiera
Customer
obiekt z bazy danychAppDb
przy użyciu podanego identyfikatora. - Jeśli nie zostanie znaleziony żaden obiekt
Customer
, zwraca odpowiedź404 Not Found
.
- Metoda pobiera
-
Zastosuj poprawkę JSON:
- Metoda ApplyTo(Object) stosuje operacje JSON Patch z patchDoc do pobranego
Customer
obiektu. - Jeśli podczas aplikacji poprawek wystąpią błędy, takie jak nieprawidłowe operacje lub konflikty, są przechwytywane przez delegata obsługi błędów. Ten delegat dodaje komunikaty o błędach do
ModelState
obiektu, którego dotyczy problem, przy użyciu nazwy typu i komunikatu o błędzie.
- Metoda ApplyTo(Object) stosuje operacje JSON Patch z patchDoc do pobranego
-
Sprawdź poprawność stanu modelu:
- Po zastosowaniu poprawki metoda sprawdza
ModelState
pod kątem błędów. - Jeśli element
ModelState
jest nieprawidłowy, na przykład z powodu błędów poprawek, zwraca400 Bad Request
odpowiedź z błędami walidacji.
- Po zastosowaniu poprawki metoda sprawdza
-
Zwróć zaktualizowanego klienta:
- Jeśli poprawka została pomyślnie zastosowana i
ModelState
jest prawidłowa, metoda zwraca zaktualizowanyCustomer
obiekt w odpowiedzi.
- Jeśli poprawka została pomyślnie zastosowana i
Przykładowa odpowiedź na błąd:
Poniższy przykład przedstawia treść odpowiedzi 400 Bad Request
dla operacji JSON Patch, gdy określona ścieżka jest nieprawidłowa:
{
"Customer": [
"The target location specified by path segment 'foobar' was not found."
]
}
Stosowanie dokumentu poprawki JSON do obiektu
W poniższych przykładach pokazano, jak za pomocą metody zastosować ApplyTo(Object) dokument poprawki JSON do obiektu.
Przykład: Zastosuj JsonPatchDocument<TModel> do obiektu
W poniższym przykładzie pokazano:
- Operacje
add
,replace
iremove
. - Operacje na właściwościach zagnieżdżonych.
- Dodawanie nowego elementu do tablicy.
- Używanie konwertera typu wyliczeniowego dla ciągów JSON w dokumencie modyfikacji 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));
Poprzedni przykład powoduje wyświetlenie następujących danych wyjściowych zaktualizowanego obiektu:
{
"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) zwykle jest zgodna z konwencjami i opcjami System.Text.Json przy przetwarzaniu JsonPatchDocument<TModel> elementu, w tym z zachowaniem kontrolowanym przez następujące opcje:
- JsonNumberHandling: czy właściwości liczbowe są odczytywane z ciągów.
- PropertyNameCaseInsensitive: Czy nazwy właściwości są rozróżniane według wielkości liter.
Kluczowe różnice między System.Text.Json a nową implementacją JsonPatchDocument<TModel>:
- Typ wykonywania obiektu docelowego, a nie zadeklarowany typ, określa, które właściwości ApplyTo(Object) są poprawiane.
- System.Text.Json deserializacja opiera się na zadeklarowanym typie w celu zidentyfikowania kwalifikujących się właściwości.
Przykład: stosowanie obiektu JsonPatchDocument z obsługą błędów
Podczas stosowania dokumentu poprawki JSON mogą wystąpić różne błędy. Na przykład obiekt docelowy może nie mieć określonej właściwości lub określona wartość może być niezgodna z typem właściwości.
Kod JSON Patch
obsługuje operację test
, która sprawdza, czy określona wartość jest równa właściwości docelowej. Jeśli tak nie jest, zwraca błąd.
W poniższym przykładzie pokazano, jak bezpiecznie obsługiwać te błędy.
Ważne
Obiekt przekazany do ApplyTo(Object) metody jest modyfikowany na miejscu. Obiekt wywołujący jest odpowiedzialny za odrzucanie zmian w przypadku niepowodzenia operacji.
// 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));
W poprzednim przykładzie są wyświetlane następujące dane wyjściowe:
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": []
}
Ograniczanie ryzyka zabezpieczeń
W przypadku korzystania z Microsoft.AspNetCore.JsonPatch.SystemTextJson
pakietu kluczowe znaczenie ma zrozumienie i ograniczenie potencjalnych zagrożeń bezpieczeństwa. W poniższych sekcjach opisano zidentyfikowane zagrożenia bezpieczeństwa związane z poprawką JSON i przedstawiono zalecane środki zaradcze w celu zapewnienia bezpiecznego użycia pakietu.
Ważne
Nie jest to wyczerpująca lista zagrożeń. Deweloperzy aplikacji muszą przeprowadzać własne przeglądy modeli zagrożeń, aby określić kompleksową listę specyficzną dla aplikacji i w razie potrzeby wymyślić odpowiednie środki zaradcze. Na przykład aplikacje, które uwidaczniają kolekcje w operacjach poprawek, powinny rozważyć potencjalne ataki związane z złożonością algorytmiczną, jeśli te operacje wstawiają lub usuwają elementy na początku kolekcji.
Aby zminimalizować zagrożenia bezpieczeństwa podczas integrowania funkcji poprawek JSON z aplikacjami, deweloperzy powinni:
- Uruchamianie kompleksowych modeli zagrożeń dla własnych aplikacji.
- Rozwiązywanie zidentyfikowanych zagrożeń.
- Postępuj zgodnie z zalecanymi środkami zaradczymi w poniższych sekcjach.
Odmowa usługi (DoS) za pośrednictwem wzmacniania pamięci
-
Scenariusz: Złośliwy klient przesyła operację
copy
, która duplikuje duże grafy obiektów wiele razy, co prowadzi do nadmiernego użycia pamięci. - Wpływ: Potencjalne warunkiOf-Memory out-Of-Memory (OOM), powodując zakłócenia usług.
-
Łagodzenie:
- Przed wywołaniem metody ApplyTo(Object)zweryfikuj przychodzące dokumenty poprawek JSON pod kątem rozmiaru i struktury.
- Walidacja musi być specyficzna dla aplikacji, ale przykładowa weryfikacja może wyglądać podobnie do następującego:
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();
}
}
Podwersja logiki biznesowej
- Scenariusz: Operacje poprawek mogą manipulować polami z niejawnymi zmiennymi (na przykład flagami wewnętrznymi, identyfikatorami lub polami obliczeniowymi), naruszając ograniczenia biznesowe.
- Wpływ: problemy z integralnością danych i niezamierzone zachowanie aplikacji.
-
Łagodzenie:
- Użyj obiektów POC (zwykłych starych obiektów CLR) z jawnie zdefiniowanymi właściwościami, które można bezpiecznie zmodyfikować.
- Unikaj uwidaczniania poufnych lub krytycznych właściwości w obiekcie docelowym.
- Jeśli obiekt POCO nie jest używany, zweryfikuj załatany obiekt po zastosowaniu operacji, aby upewnić się, że reguły biznesowe i zasady niezmienności nie są naruszone.
- Użyj obiektów POC (zwykłych starych obiektów CLR) z jawnie zdefiniowanymi właściwościami, które można bezpiecznie zmodyfikować.
Uwierzytelnianie i autoryzacja
- Scenariusz: Nieuwierzytelniony lub nieautoryzowani klienci wysyłają złośliwe żądania poprawek JSON.
- Wpływ: Nieautoryzowany dostęp do modyfikowania poufnych danych lub zakłócania działania aplikacji.
-
Łagodzenie:
- Ochrona punktów końcowych akceptujących żądania poprawek JSON przy użyciu odpowiednich mechanizmów uwierzytelniania i autoryzacji.
- Ogranicz dostęp do zaufanych klientów lub użytkowników z odpowiednimi uprawnieniami.
Uzyskiwanie kodu
Wyświetl lub pobierz kod przykładowy. (Jak pobrać).
Aby przetestować przykład, uruchom aplikację i wyślij żądania HTTP przy użyciu następujących ustawień:
- Adres URL:
http://localhost:{port}/jsonpatch/jsonpatchwithmodelstate
- Metoda HTTP:
PATCH
- Nagłówek:
Content-Type: application/json-patch+json
- Treść: skopiuj i wklej jeden z przykładów dokumentów poprawek JSON z folderu projektu JSON .
Dodatkowe zasoby
W tym artykule wyjaśniono, jak obsługiwać żądania poprawek JSON w internetowym interfejsie API platformy ASP.NET Core.
Ważne
Standard poprawki JSON ma nieodłączne zagrożenia bezpieczeństwa. Ta implementacja nie próbuje ograniczyć tych nieodłącznych zagrożeń bezpieczeństwa. Jest to odpowiedzialność dewelopera za zapewnienie, że dokument poprawki JSON jest bezpieczny do zastosowania do obiektu docelowego. Aby uzyskać więcej informacji, zobacz sekcję Ograniczanie ryzyka zabezpieczeń .
Instalacja pakietu
Obsługa poprawek JSON w internetowym interfejsie API platformy ASP.NET Core jest oparta i Newtonsoft.Json
wymaga Microsoft.AspNetCore.Mvc.NewtonsoftJson
pakietu NuGet.
Aby włączyć obsługę poprawek JSON:
Microsoft.AspNetCore.Mvc.NewtonsoftJson
Zainstaluj pakiet NuGet.Wywołaj polecenie AddNewtonsoftJson. Na przykład:
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers() .AddNewtonsoftJson(); var app = builder.Build(); app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();
AddNewtonsoftJson
Zastępuje domyślne System.Text.Json
formatery danych wejściowych i wyjściowych używane do formatowania całej zawartości JSON. Ta metoda rozszerzenia jest zgodna z następującymi metodami rejestracji usługi MVC:
JsonPatch wymaga ustawienia nagłówka Content-Type
na application/json-patch+json
.
Dodawanie obsługi poprawki JSON w przypadku korzystania z pliku System.Text.Json
Formater System.Text.Json
danych wejściowych oparty na protokole nie obsługuje poprawki JSON. Aby dodać obsługę poprawek JSON przy użyciu polecenia Newtonsoft.Json
, pozostawiając inne formatery danych wejściowych i wyjściowych bez zmian:
Microsoft.AspNetCore.Mvc.NewtonsoftJson
Zainstaluj pakiet NuGet.Aktualizacja
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(); } }
Powyższy kod tworzy wystąpienie NewtonsoftJsonPatchInputFormatter obiektu i wstawia je jako pierwszy wpis w kolekcji MvcOptions.InputFormatters . Ta kolejność rejestracji gwarantuje, że:
-
NewtonsoftJsonPatchInputFormatter
przetwarza żądania poprawek JSON. - Istniejące
System.Text.Json
elementy wejściowe i formatujące przetwarzają wszystkie inne żądania i odpowiedzi w formacie JSON.
Newtonsoft.Json.JsonConvert.SerializeObject
Użyj metody , aby serializować element JsonPatchDocument.
PATCH HTTP request method (Metoda żądania HTTP PATCH)
Metody PUT i PATCH służą do aktualizowania istniejącego zasobu. Różnica między nimi polega na tym, że PUT zastępuje cały zasób, podczas gdy PATCH określa tylko zmiany.
Poprawka JSON
Poprawka JSON to format określający aktualizacje, które mają być stosowane do zasobu. Dokument poprawki JSON zawiera tablicę operacji. Każda operacja identyfikuje określony typ zmiany. Przykłady takich zmian obejmują dodanie elementu tablicy lub zastąpienie wartości właściwości.
Na przykład następujące dokumenty JSON reprezentują zasób, dokument poprawki JSON dla zasobu i wynik zastosowania operacji patch.
Przykład zasobu
{
"customerName": "John",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
}
]
}
Przykład poprawki JSON
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
W powyższym kodzie JSON:
- Właściwość
op
wskazuje typ operacji. - Właściwość
path
wskazuje element do zaktualizowania. - Właściwość
value
udostępnia nową wartość.
Zasób po poprawce
Oto zasób po zastosowaniu poprzedniego dokumentu poprawki JSON:
{
"customerName": "Barry",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
},
{
"orderName": "Order2",
"orderType": null
}
]
}
Zmiany wprowadzone przez zastosowanie dokumentu poprawki JSON do zasobu są niepodzielne. Jeśli jakakolwiek operacja na liście nie powiedzie się, nie zostanie zastosowana żadna operacja na liście.
Składnia XPath
Właściwość path obiektu operacji ma ukośniki między poziomami. Na przykład "/address/zipCode"
.
Indeksy oparte na zerach służą do określania elementów tablicy. Pierwszym elementem addresses
tablicy będzie wartość /addresses/0
. Na add
końcu tablicy użyj łącznika (-
), a nie numeru indeksu: /addresses/-
.
Operacje
W poniższej tabeli przedstawiono obsługiwane operacje zdefiniowane w specyfikacji poprawki JSON:
Operacja | Uwagi |
---|---|
add |
Dodaj właściwość lub element tablicy. Dla istniejącej właściwości: ustaw wartość. |
remove |
Usuń właściwość lub element tablicy. |
replace |
To samo, co remove następuje add w tej samej lokalizacji. |
move |
Tak samo jak remove ze źródła, a następnie add do miejsca docelowego przy użyciu wartości ze źródła. |
copy |
Tak samo jak add w przypadku lokalizacji docelowej przy użyciu wartości ze źródła. |
test |
Zwraca kod stanu powodzenia, jeśli wartość na path = podano value . |
Poprawka JSON w ASP.NET Core
Implementacja ASP.NET Core poprawki JSON jest dostępna w pakiecie NuGet Microsoft.AspNetCore.JsonPatch .
Kod metody akcji
W kontrolerze interfejsu API metoda akcji dla poprawki JSON:
- Jest adnotacją z atrybutem
HttpPatch
. - Akceptuje element JsonPatchDocument<TModel>, zazwyczaj z elementem
[FromBody]
. - Wywołuje ApplyTo(Object) dokument poprawki, aby zastosować zmiany.
Oto przykład:
[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);
}
}
Ten kod z przykładowej aplikacji działa z następującym 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; }
}
Przykładowa metoda akcji:
- Tworzy element
Customer
. - Stosuje poprawkę.
- Zwraca wynik w treści odpowiedzi.
W rzeczywistej aplikacji kod pobiera dane z magazynu, takiego jak baza danych, i aktualizuje bazę danych po zastosowaniu poprawki.
Stan modelu
Powyższy przykład metody akcji wywołuje przeciążenie ApplyTo
, które przyjmuje stan modelu jako jeden z jego parametrów. Dzięki tej opcji możesz otrzymywać komunikaty o błędach w odpowiedziach. W poniższym przykładzie przedstawiono treść odpowiedzi 400 Nieprawidłowe żądanie dla test
operacji:
{
"Customer": [
"The current value 'John' at path 'customerName' != test value 'Nancy'."
]
}
Obiekty dynamiczne
Poniższy przykład metody akcji pokazuje, jak zastosować poprawkę do obiektu dynamicznego:
[HttpPatch]
public IActionResult JsonPatchForDynamic([FromBody]JsonPatchDocument patch)
{
dynamic obj = new ExpandoObject();
patch.ApplyTo(obj);
return Ok(obj);
}
Operacja dodawania
- Jeśli
path
wskazuje element tablicy: wstawia nowy element przed elementem określonym przezpath
. - Jeśli
path
wskazuje właściwość: ustawia wartość właściwości. - Jeśli
path
wskazuje na nieistnieną lokalizację:- Jeśli zasób do stosowania poprawek jest obiektem dynamicznym: dodaje właściwość.
- Jeśli zasób do stosowania poprawek jest obiektem statycznym: żądanie kończy się niepowodzeniem.
Poniższy przykładowy dokument poprawki ustawia wartość CustomerName
i dodaje Order
obiekt na końcu Orders
tablicy.
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Operacja usuwania
- Jeśli
path
wskazuje element tablicy: usuwa element. - Jeśli
path
wskazuje właściwość:- Jeśli zasób do poprawki jest obiektem dynamicznym: usuwa właściwość .
- Jeśli zasób do poprawki jest obiektem statycznym:
- Jeśli właściwość ma wartość null: ustawia ją na wartość null.
- Jeśli właściwość jest niemożliwa do wartości null, ustawia ją na
default<T>
wartość .
Następujące przykładowe poprawki dokumentów ustawiają wartość CustomerName
null i usuwają Orders[0]
element :
[
{
"op": "remove",
"path": "/customerName"
},
{
"op": "remove",
"path": "/orders/0"
}
]
Operacja zastępowania
Ta operacja jest funkcjonalnie taka sama jak remove
po nim .add
Poniższy przykładowy dokument poprawki ustawia wartość CustomerName
i zastępuje Orders[0]
element nowym Order
obiektem:
[
{
"op": "replace",
"path": "/customerName",
"value": "Barry"
},
{
"op": "replace",
"path": "/orders/0",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Operacja przenoszenia
- Jeśli
path
wskazuje element tablicy: kopiujefrom
element do lokalizacjipath
elementu, a następnie uruchamia operacjęremove
na elemeciefrom
. - Jeśli
path
wskazuje właściwość: kopiuje wartośćfrom
właściwości dopath
właściwości, a następnie uruchamia operacjęremove
nafrom
właściwości. - Jeśli
path
wskazuje na nieistnieną właściwość:- Jeśli zasób do stosowania poprawek jest obiektem statycznym: żądanie kończy się niepowodzeniem.
- Jeśli zasób do stosowania poprawek jest obiektem dynamicznym: kopiuje
from
właściwość do lokalizacji wskazanej przezpath
element , uruchamia operacjęremove
nafrom
właściwości .
Następujący przykładowy dokument poprawki:
- Kopiuje wartość
Orders[0].OrderName
doCustomerName
. - Ustawia
Orders[0].OrderName
wartość null. - Przechodzi
Orders[1]
do przedOrders[0]
.
[
{
"op": "move",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "move",
"from": "/orders/1",
"path": "/orders/0"
}
]
Operacja kopiowania
Ta operacja jest funkcjonalnie taka sama jak move
operacja bez ostatniego remove
kroku.
Następujący przykładowy dokument poprawki:
- Kopiuje wartość
Orders[0].OrderName
doCustomerName
. - Wstawia kopię
Orders[1]
przed elementemOrders[0]
.
[
{
"op": "copy",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "copy",
"from": "/orders/1",
"path": "/orders/0"
}
]
Operacja testowa
Jeśli wartość w lokalizacji wskazanej przez path
jest inna niż wartość podana w value
elemecie , żądanie zakończy się niepowodzeniem. W takim przypadku całe żądanie PATCH kończy się niepowodzeniem, nawet jeśli wszystkie inne operacje w dokumencie poprawki zakończyłyby się powodzeniem.
Operacja test
jest często używana do zapobiegania aktualizacji w przypadku konfliktu współbieżności.
Następujący przykładowy dokument poprawki nie ma wpływu, jeśli początkowa wartość CustomerName
to "Jan", ponieważ test kończy się niepowodzeniem:
[
{
"op": "test",
"path": "/customerName",
"value": "Nancy"
},
{
"op": "add",
"path": "/customerName",
"value": "Barry"
}
]
Uzyskiwanie kodu
Wyświetl lub pobierz kod przykładowy. (Jak pobrać).
Aby przetestować przykład, uruchom aplikację i wyślij żądania HTTP przy użyciu następujących ustawień:
- Adres URL:
http://localhost:{port}/jsonpatch/jsonpatchwithmodelstate
- Metoda HTTP:
PATCH
- Nagłówek:
Content-Type: application/json-patch+json
- Treść: skopiuj i wklej jeden z przykładów dokumentów poprawek JSON z folderu projektu JSON .
Ograniczanie ryzyka zabezpieczeń
W przypadku korzystania z pakietu Microsoft.AspNetCore.JsonPatch
z implementacją opartą na Newtonsoft.Json
, kluczowe jest zrozumienie i ograniczenie potencjalnych zagrożeń bezpieczeństwa. W poniższych sekcjach opisano zidentyfikowane zagrożenia bezpieczeństwa związane z poprawką JSON i przedstawiono zalecane środki zaradcze w celu zapewnienia bezpiecznego użycia pakietu.
Ważne
Nie jest to wyczerpująca lista zagrożeń. Deweloperzy aplikacji muszą przeprowadzać własne przeglądy modeli zagrożeń, aby określić kompleksową listę specyficzną dla aplikacji i w razie potrzeby wymyślić odpowiednie środki zaradcze. Na przykład aplikacje, które uwidaczniają kolekcje w operacjach poprawek, powinny rozważyć potencjalne ataki związane z złożonością algorytmiczną, jeśli te operacje wstawiają lub usuwają elementy na początku kolekcji.
Uruchamiając kompleksowe modele zagrożeń dla własnych aplikacji i zwracając się do zidentyfikowanych zagrożeń, stosując poniższe zalecane środki zaradcze, konsumenci tych pakietów mogą zintegrować funkcje poprawki JSON z aplikacjami, jednocześnie minimalizując zagrożenia bezpieczeństwa.
Odmowa usługi (DoS) za pośrednictwem wzmacniania pamięci
-
Scenariusz: Złośliwy klient przesyła operację
copy
, która duplikuje duże grafy obiektów wiele razy, co prowadzi do nadmiernego użycia pamięci. - Wpływ: Potencjalne warunkiOf-Memory out-Of-Memory (OOM), powodując zakłócenia usług.
-
Łagodzenie:
- Przed wywołaniem metody
ApplyTo
zweryfikuj przychodzące dokumenty poprawek JSON pod kątem rozmiaru i struktury. - Walidacja musi być specyficzna dla aplikacji, ale przykładowa weryfikacja może wyglądać podobnie do następującego:
- Przed wywołaniem metody
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();
}
}
Podwersja logiki biznesowej
- Scenariusz: Operacje poprawek mogą manipulować polami z niejawnymi zmiennymi (na przykład flagami wewnętrznymi, identyfikatorami lub polami obliczeniowymi), naruszając ograniczenia biznesowe.
- Wpływ: problemy z integralnością danych i niezamierzone zachowanie aplikacji.
-
Łagodzenie:
- Użyj obiektów POCO z jawnie zdefiniowanymi właściwościami, które można bezpiecznie modyfikować.
- Unikaj uwidaczniania poufnych lub krytycznych właściwości w obiekcie docelowym.
- Jeśli nie jest używany żaden obiekt POCO, zweryfikuj poprawiony obiekt po zastosowaniu operacji, aby upewnić się, że reguły biznesowe i niezmienne nie są naruszone.
Uwierzytelnianie i autoryzacja
- Scenariusz: Nieuwierzytelniony lub nieautoryzowani klienci wysyłają złośliwe żądania poprawek JSON.
- Wpływ: Nieautoryzowany dostęp do modyfikowania poufnych danych lub zakłócania działania aplikacji.
-
Łagodzenie:
- Ochrona punktów końcowych akceptujących żądania poprawek JSON przy użyciu odpowiednich mechanizmów uwierzytelniania i autoryzacji.
- Ogranicz dostęp do zaufanych klientów lub użytkowników z odpowiednimi uprawnieniami.
Dodatkowe zasoby
W tym artykule wyjaśniono, jak obsługiwać żądania poprawek JSON w internetowym interfejsie API platformy ASP.NET Core.
Ważne
Standard poprawki JSON ma nieodłączne zagrożenia bezpieczeństwa. Ponieważ te zagrożenia są związane ze standardem poprawki JSON, ta implementacja nie próbuje ograniczyć ryzyka związanego z zabezpieczeniami. Jest to odpowiedzialność dewelopera za zapewnienie, że dokument poprawki JSON jest bezpieczny do zastosowania do obiektu docelowego. Aby uzyskać więcej informacji, zobacz sekcję Ograniczanie ryzyka zabezpieczeń .
Instalacja pakietu
Aby włączyć obsługę poprawek JSON w aplikacji, wykonaj następujące kroki:
Microsoft.AspNetCore.Mvc.NewtonsoftJson
Zainstaluj pakiet NuGet.Zaktualizuj metodę projektu
Startup.ConfigureServices
, aby wywołać AddNewtonsoftJsonmetodę . Na przykład:services .AddControllersWithViews() .AddNewtonsoftJson();
AddNewtonsoftJson
jest zgodny z metodami rejestracji usługi MVC:
Poprawka JSON, AddNewtonsoftJson i System.Text.Json
AddNewtonsoftJson
System.Text.Json
Zastępuje - oparte formatery danych wejściowych i wyjściowych używane do formatowania całej zawartości JSON. Aby dodać obsługę poprawki JSON przy użyciu polecenia Newtonsoft.Json
, pozostawiając inne formatery bez zmian, zaktualizuj metodę projektu Startup.ConfigureServices
w następujący sposób:
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();
}
Powyższy kod wymaga Microsoft.AspNetCore.Mvc.NewtonsoftJson
pakietu i następujących using
instrukcji:
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
Użyj metody , aby serializować kod JsonPatchDocument.
PATCH HTTP request method (Metoda żądania HTTP PATCH)
Metody PUT i PATCH służą do aktualizowania istniejącego zasobu. Różnica między nimi polega na tym, że PUT zastępuje cały zasób, podczas gdy PATCH określa tylko zmiany.
Poprawka JSON
Poprawka JSON to format określający aktualizacje, które mają być stosowane do zasobu. Dokument poprawki JSON zawiera tablicę operacji. Każda operacja identyfikuje określony typ zmiany. Przykłady takich zmian obejmują dodanie elementu tablicy lub zastąpienie wartości właściwości.
Na przykład następujące dokumenty JSON reprezentują zasób, dokument poprawki JSON dla zasobu i wynik zastosowania operacji patch.
Przykład zasobu
{
"customerName": "John",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
}
]
}
Przykład poprawki JSON
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
W powyższym kodzie JSON:
- Właściwość
op
wskazuje typ operacji. - Właściwość
path
wskazuje element do zaktualizowania. - Właściwość
value
udostępnia nową wartość.
Zasób po poprawce
Oto zasób po zastosowaniu poprzedniego dokumentu poprawki JSON:
{
"customerName": "Barry",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
},
{
"orderName": "Order2",
"orderType": null
}
]
}
Zmiany wprowadzone przez zastosowanie dokumentu poprawki JSON do zasobu są niepodzielne. Jeśli jakakolwiek operacja na liście nie powiedzie się, nie zostanie zastosowana żadna operacja na liście.
Składnia XPath
Właściwość path obiektu operacji ma ukośniki między poziomami. Na przykład "/address/zipCode"
.
Indeksy oparte na zerach służą do określania elementów tablicy. Pierwszym elementem addresses
tablicy będzie wartość /addresses/0
. Na add
końcu tablicy użyj łącznika (-
), a nie numeru indeksu: /addresses/-
.
Operacje
W poniższej tabeli przedstawiono obsługiwane operacje zdefiniowane w specyfikacji poprawki JSON:
Operacja | Uwagi |
---|---|
add |
Dodaj właściwość lub element tablicy. Dla istniejącej właściwości: ustaw wartość. |
remove |
Usuń właściwość lub element tablicy. |
replace |
To samo, co remove następuje add w tej samej lokalizacji. |
move |
Tak samo jak remove ze źródła, a następnie add do miejsca docelowego przy użyciu wartości ze źródła. |
copy |
Tak samo jak add w przypadku lokalizacji docelowej przy użyciu wartości ze źródła. |
test |
Zwraca kod stanu powodzenia, jeśli wartość na path = podano value . |
Poprawka JSON w ASP.NET Core
Implementacja ASP.NET Core poprawki JSON jest dostępna w pakiecie NuGet Microsoft.AspNetCore.JsonPatch .
Kod metody akcji
W kontrolerze interfejsu API metoda akcji dla poprawki JSON:
- Jest adnotacją z atrybutem
HttpPatch
. - Akceptuje element
JsonPatchDocument<T>
, zazwyczaj z elementem[FromBody]
. - Wywołuje
ApplyTo
dokument poprawki, aby zastosować zmiany.
Oto przykład:
[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);
}
}
Ten kod z przykładowej aplikacji działa z następującym 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; }
}
}
Przykładowa metoda akcji:
- Tworzy element
Customer
. - Stosuje poprawkę.
- Zwraca wynik w treści odpowiedzi.
W rzeczywistej aplikacji kod pobiera dane z magazynu, takiego jak baza danych, i aktualizuje bazę danych po zastosowaniu poprawki.
Stan modelu
Powyższy przykład metody akcji wywołuje przeciążenie ApplyTo
, które przyjmuje stan modelu jako jeden z jego parametrów. Dzięki tej opcji możesz otrzymywać komunikaty o błędach w odpowiedziach. W poniższym przykładzie przedstawiono treść odpowiedzi 400 Nieprawidłowe żądanie dla test
operacji:
{
"Customer": [
"The current value 'John' at path 'customerName' is not equal to the test value 'Nancy'."
]
}
Obiekty dynamiczne
Poniższy przykład metody akcji pokazuje, jak zastosować poprawkę do obiektu dynamicznego:
[HttpPatch]
public IActionResult JsonPatchForDynamic([FromBody]JsonPatchDocument patch)
{
dynamic obj = new ExpandoObject();
patch.ApplyTo(obj);
return Ok(obj);
}
Operacja dodawania
- Jeśli
path
wskazuje element tablicy: wstawia nowy element przed elementem określonym przezpath
. - Jeśli
path
wskazuje właściwość: ustawia wartość właściwości. - Jeśli
path
wskazuje na nieistnieną lokalizację:- Jeśli zasób do stosowania poprawek jest obiektem dynamicznym: dodaje właściwość.
- Jeśli zasób do stosowania poprawek jest obiektem statycznym: żądanie kończy się niepowodzeniem.
Poniższy przykładowy dokument poprawki ustawia wartość CustomerName
i dodaje Order
obiekt na końcu Orders
tablicy.
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Operacja usuwania
- Jeśli
path
wskazuje element tablicy: usuwa element. - Jeśli
path
wskazuje właściwość:- Jeśli zasób do poprawki jest obiektem dynamicznym: usuwa właściwość .
- Jeśli zasób do poprawki jest obiektem statycznym:
- Jeśli właściwość ma wartość null: ustawia ją na wartość null.
- Jeśli właściwość jest niemożliwa do wartości null, ustawia ją na
default<T>
wartość .
Następujące przykładowe poprawki dokumentów ustawiają wartość CustomerName
null i usuwają Orders[0]
element :
[
{
"op": "remove",
"path": "/customerName"
},
{
"op": "remove",
"path": "/orders/0"
}
]
Operacja zastępowania
Ta operacja jest funkcjonalnie taka sama jak remove
po nim .add
Poniższy przykładowy dokument poprawki ustawia wartość CustomerName
i zastępuje Orders[0]
element nowym Order
obiektem:
[
{
"op": "replace",
"path": "/customerName",
"value": "Barry"
},
{
"op": "replace",
"path": "/orders/0",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Operacja przenoszenia
- Jeśli
path
wskazuje element tablicy: kopiujefrom
element do lokalizacjipath
elementu, a następnie uruchamia operacjęremove
na elemeciefrom
. - Jeśli
path
wskazuje właściwość: kopiuje wartośćfrom
właściwości dopath
właściwości, a następnie uruchamia operacjęremove
nafrom
właściwości. - Jeśli
path
wskazuje na nieistnieną właściwość:- Jeśli zasób do stosowania poprawek jest obiektem statycznym: żądanie kończy się niepowodzeniem.
- Jeśli zasób do stosowania poprawek jest obiektem dynamicznym: kopiuje
from
właściwość do lokalizacji wskazanej przezpath
element , uruchamia operacjęremove
nafrom
właściwości .
Następujący przykładowy dokument poprawki:
- Kopiuje wartość
Orders[0].OrderName
doCustomerName
. - Ustawia
Orders[0].OrderName
wartość null. - Przechodzi
Orders[1]
do przedOrders[0]
.
[
{
"op": "move",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "move",
"from": "/orders/1",
"path": "/orders/0"
}
]
Operacja kopiowania
Ta operacja jest funkcjonalnie taka sama jak move
operacja bez ostatniego remove
kroku.
Następujący przykładowy dokument poprawki:
- Kopiuje wartość
Orders[0].OrderName
doCustomerName
. - Wstawia kopię
Orders[1]
przed elementemOrders[0]
.
[
{
"op": "copy",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "copy",
"from": "/orders/1",
"path": "/orders/0"
}
]
Operacja testowa
Jeśli wartość w lokalizacji wskazanej przez path
jest inna niż wartość podana w value
elemecie , żądanie zakończy się niepowodzeniem. W takim przypadku całe żądanie PATCH kończy się niepowodzeniem, nawet jeśli wszystkie inne operacje w dokumencie poprawki zakończyłyby się powodzeniem.
Operacja test
jest często używana do zapobiegania aktualizacji w przypadku konfliktu współbieżności.
Następujący przykładowy dokument poprawki nie ma wpływu, jeśli początkowa wartość CustomerName
to "Jan", ponieważ test kończy się niepowodzeniem:
[
{
"op": "test",
"path": "/customerName",
"value": "Nancy"
},
{
"op": "add",
"path": "/customerName",
"value": "Barry"
}
]
Uzyskiwanie kodu
Wyświetl lub pobierz kod przykładowy. (Jak pobrać).
Aby przetestować przykład, uruchom aplikację i wyślij żądania HTTP przy użyciu następujących ustawień:
- Adres URL:
http://localhost:{port}/jsonpatch/jsonpatchwithmodelstate
- Metoda HTTP:
PATCH
- Nagłówek:
Content-Type: application/json-patch+json
- Treść: skopiuj i wklej jeden z przykładów dokumentów poprawek JSON z folderu projektu JSON .