Web API - Come impedire il POST -ing delle entità con valori di ID personalizzati

2

Diciamo che ho il seguente modello:

public class Product
{        
    public string Id { get; set; }
    public string Name { get; set; }
    public string Category { get; set; }
    public decimal Price { get; set; }
}

Ora vorrei davvero consentire alle persone di aggiungere e visualizzare il mio catalogo di prodotti. Quindi, creo il seguente controller:

Nota: si prega di non essere troppo schifato dalla lista statica. So che è sbagliato.

public class ProductsController : ApiController
{
    static readonly List<Product> products = new List<Product>();

    // ...

    [HttpPost]
    public void AddProduct(Product value)
    {
        products.Add(product);
    }
}

Come forse avrai notato, attualmente sto consentendo alle persone di aggiungere nuovi prodotti con valori personalizzati di Id . Questo non mi sembra giusto. Dovrei avere il controllo degli identificatori dei miei prodotti, giusto? Non voglio dare alle persone l'idea di poterle impostare.

La mia tentata soluzione era creare un DTO per il mio modello di prodotto, quindi installare il pacchetto AutoMapper .

Ecco il DTO:

public class ProductDto
{
    public string Name { get; set; }
    public string Category { get; set; }
    public decimal Price { get; set; }
}

Ed ecco il nuovo controller:

public class ProductsController : ApiController
{
    static readonly List<Product> products = new List<Product>();

    // ...

    [HttpPost]
    public void AddProduct(ProductDto value)
    {
        Product product = Mapper.Map<Product>(value);
        product.Id = Guid.NewGuid().ToString();

        products.Add(product);
    }
}

È ragionevole? Esiste un approccio più semplice e più canonico?

Grazie!

    
posta kylemart 09.08.2017 - 18:37
fonte

3 risposte

2

In realtà ... indietro nel giorno (e ancora oggi) era molto comune non dare alle persone la possibilità di generare id sul lato client per un semplice motivo: gli ID erano valori interi auto incrementati e venivano generati dal motore di database.

Ma ci sono problemi con questo approccio:

  1. ti stai legando all'implementazione del database,
  2. gli ID generati automaticamente non sono affatto sicuri e sono inclini a indovinare l'id - una tecnica in cui puoi indovinare quante risorse ci sono nei tuoi database incrementando l'id di uno fino a quando non ricevi risposta non trovata.

Le persone hanno tentato di risolvere il secondo problema usando qualche offuscamento dell'ID e / o trovato un modo diverso per identificare una risorsa all'interno del sistema e ultimamente è diventato sempre più popolare usare Guidi / Uuids invece.

Ma poi la domanda appariva: Se gli id non sono più generati dal motore del database e legati al backend e gli Uuid V4 sono praticamente unici (il rischio di collisione è praticamente inesistente per qualsiasi progetto di dimensioni regolari), perché abbiamo anche bisogno del server per generarli?

E la risposta è stata: non lo hai.

Ok, ad essere onesti, se tutto il tuo sistema funziona in linea e non può funzionare senza un server, forse il server per generare Uuid va ancora bene. Ma la singola pagina e le applicazioni mobili supportate dalle API REST per la sincronizzazione multipiattaforma sono diventate sempre più popolari. Avere il client generare gli Uuid e quindi essere in grado di usarli istantaneamente (anche per riferimenti incrociati) rende la tua applicazione molto utilizzabile anche quando è offline.

Potresti obiettare che puoi creare un'applicazione funzionante offline con id regolari, generando in modo efficace id locali personalizzati e sincronizzandoli con gli id sul server. Il fatto è che con Uuids puoi saltare questa sincronizzazione e mappare e trattare il tuo locale come se fosse già sul server, perché gli ID rimangono gli stessi.

Quindi se pensi di avere il controllo dell'identificazione della tua risorsa, non lo fai.

    
risposta data 09.08.2017 - 21:14
fonte
2

I punti coppia qui:

  1. Devi possedere il tuo identificatore univoco interno, che non deve essere esposto tramite l'API, né per l'aggiunta o la visualizzazione. L'identificatore è per il tuo database per creare relazioni chiave. L'identificatore deve essere generato dal tuo sistema (ad esempio utilizzando una colonna IDENTITY ) quando vengono ricevute le richieste per aggiungere prodotti.

  2. L'utente finale dovrebbe essere in grado di inviare prodotti con un ID azienda (forse derivato dal contesto di accesso) più un identificativo di prodotto specifico dell'azienda come SKU o codice UPC . Questo dovrebbe essere il loro unico numero di riferimento. È loro responsabilità garantire che questi identificatori non entrino in collisione con altri prodotti all'interno di tale ID aziendale. Dal punto di vista del tuo sistema, questo campo potrebbe essere chiamato ExternalProductID e formerebbe una chiave univoca solo se combinato con CompanyID.

  3. Se fossi in te non includerei il prezzo nel prodotto. Il prezzo è una proprietà di un'offerta per un prodotto. Mentre i prodotti sono per sempre, le offerte vanno e vengono (quando il prezzo cambia). Se non lo fai in questo modo avrai problemi con gli aggiornamenti e il riutilizzo dell'ID prodotto.

risposta data 10.08.2017 - 22:02
fonte
1

Assumerò qui che gli ID prodotto non sono effettivamente richiesti per essere usati dagli utenti ed è una cosa interna usata nella tua API quindi non avrà importanza di cosa sia.

1) Crea il tuo ID prodotto utilizzando una sequenza o qualsiasi altra cosa come è normale. Non lasciare che i clienti scelgano i loro ID.

2) Ogni volta che esporti il tuo catalogo o un ID prodotto per qualsiasi motivo, cripta (non hash) l'ID prodotto usando l'ID di accesso dell'utente + un po 'di sale o altra chiave. Se non è necessario che il client faccia riferimento all'ID del prodotto tra le sessioni, è possibile utilizzare l'ID di sessione.

3) Quando qualcuno aggiunge un nuovo prodotto, lo aggiungi al tuo DB e crea un nuovo ID usando la sequenza. Restituisci il codice crittografato al client per un uso continuativo.

4) Quando si riceve un ID prodotto dal client, decodificare a seconda dei casi.

5) Solo internamente usa sempre le tue chiavi di identità.

Il vantaggio di questo è che

a) Hai una chiave univoca che non può essere scelta di nuovo.

b) I clienti non possono indovinare un tasto in modo efficace

c) Anche se qualcuno scopre la versione di qualcun altro, non funzionerà al di fuori del loro accesso (o sessione a seconda di cosa decidi).

d) Hai un database "normale" sul back-end.

    
risposta data 11.08.2017 - 02:21
fonte

Leggi altre domande sui tag