10

Ho un'applicazione ASP.NET MVC che utilizza gli attributi di autorizzazione su controller e azioni. Questo ha funzionato bene, ma una nuova ruga si è manifestata.ASP.NET MVC: autorizzazione all'interno di un'azione - Modelli suggeriti o si tratta di un odore?

Oggetto: Spedizione

Ruoli: Spedizione, contabilità, utenti generali

La spedizione si muove attraverso un flusso di lavoro. Nello stato A può essere modificato solo dalla spedizione. Nello stato B può essere modificato solo da Contabilità.

Possiedo un controller di spedizione e un'azione di modifica. Posso inserire un attributo Authorization per limitare l'azione Edit solo a questi due ruoli, ma questo non fa distinzione tra lo stato in cui si trova la spedizione. Avrei bisogno di fare un po 'di autorizzazione all'interno dell'azione prima della chiamata di servizio per determinare se l'utente è veramente autorizzato ad eseguire l'azione di modifica.

Così ho lasciato con due domande:

1) Che cosa è un buon modo per avere l'autorizzazione all'interno di un'azione. L'Azione controller chiama un servizio e il servizio effettua quindi le chiamate appropriate all'oggetto Spedizione (quantità di aggiornamento, data di aggiornamento, ecc.). So per certo che voglio che l'oggetto della spedizione sia indipendente dai requisiti di autorizzazione. D'altra parte, non ho una vera comprensione se volessi che l'oggetto di servizio fosse a conoscenza dell'autorizzazione o meno. Ci sono dei buoni schemi per questo?

2) Il mio problema è in realtà un sintomo di progettazione errata? Invece di ShipmentController dovrei avere StateAShipmentController e StateBShipmentController? Non ho alcun polimorfismo incorporato nell'oggetto di spedizione (lo stato è solo un enum), ma forse dovrei e forse i controllori dovrebbero riflettere questo.

Immagino di dover cercare soluzioni più generali, non specifiche per il mio caso. Volevo solo fornire un esempio per illustrare la domanda.

Grazie!

+0

Perché non creare il proprio filtro di azione [Autorizza] per il materiale relativo alla spedizione? –

+0

creare il tuo filtro [Autorizza] sarebbe davvero una pessima idea, ed è uno che il team di sviluppo di ASP.NET MVC ha davvero scoraggiato davvero molto bene –

+0

@Josh; Non sono d'accordo. Non è una "idea davvero pessima", è solo una che dovrebbe essere affrontata con la dovuta attenzione. Non ho visto nessun articolo pubblico su scoraggiarlo affatto, tanto meno con diversi "davvero" e "fortemente". L'unico vero 'trucco' della mia conoscenza è che vuoi ereditare dall'attributo Authorize fornito dal framework, perché in questo modo puoi assicurarti che venga licenziato in modo affidabile nel posto giusto. – Paul

risposta

2

L'attributo di autorizzazione può ottenere la spedizione dai parametri di azione o dai dati di percorso e quindi prendere una decisione.

Per il numero 1, esistono numerosi modelli che consentono un comportamento avanzato negli oggetti di dominio. Nel doppio invio, si passa un riferimento a un'astrazione di servizio (interfaccia) a un metodo sull'oggetto. Quindi può fare la sua cosa. Puoi anche scrivere un servizio applicativo che prende la spedizione e fa il lavoro.

Al numero 2, non necessariamente. Potresti aver bisogno di astrarre il concetto di "Spedizione contestuale" in un servizio che capisca quale contesto di spedizione ti trovi. Ma lo farei a YAGNI fino a quando non ne avrai più bisogno.

1

Si potrebbe dare un'occhiata a Rhino.Security, potrebbe essere utilizzato per implementare l'autorizzazione utente in questi tipi di scenari.

3

Non vedo alcun problema con un metodo Action che esegue ulteriori controlli di autorizzazione al suo interno. Puoi sfruttare il fornitore di ruoli per l'autorizzazione a grana fine che stai cercando. Per favore scusa la mia sintassi qui - è probabile che sia difficile e non l'ho ancora testato.

[Authorize(Roles="Shipping, Accounting")] 
public ActionResult Edit(int id) 
{ 
    Shipment shipment = repos.GetShipment(id); 


    switch (shipment.State) 
    { 
     case ShipmentState.A: 
     if (Roles.IsUserInRole("Shipping")) 
       return View(shipment); 
     else 
       return View("NotAuthorized"); 
     break; 
     case ShipmentState.B: 
     if (Roles.IsUserInRole("Accounting")) 
       return View(shipment); 
     else 
       return View("NotAuthorized"); 
     break; 
     default: 
       return View("NotAuthorized"); 
    } 
} 
+0

Mentre quella è una soluzione "semplice", odora un po '. L'hardcoding dell'autorizzazione sul controller viola l'SRP e dovrebbe per lo meno essere rifattorizzato nella propria classe. –

+0

Questo esempio quasi richiede un'attuazione dello schema di stato. – Paul

+1

heh si certo! Per quanto fosse semplicistico, volevo essere sicuro di aver affrontato la domanda dell'OP, piuttosto che impantanarmi nei dettagli. –

1

In aggiunta alla risposta di cui sopra, è possibile restituire un HttpUnauthorizedResult invece di creare il proprio punto di vista per NotAuthorized.Questo reindirizzerà alla pagina di accesso e si comporterà come il solito attributo [Autorizza]

Problemi correlati