API REST basata sul ruolo?


27

Sto creando un'API REST per la quale diversi utenti con ruoli diversi avranno accesso alle risorse in esso contenute.

Per semplificare la portata prendiamo il dominio "studente / insegnante / classe":

GET /students è la risorsa a cui accedere.

Gli utenti potrebbero avere ruoli come Studente e / o Insegnante

Gli studenti avranno accesso solo agli studenti delle loro classi. Gli insegnanti avranno accesso agli studenti delle classi che insegnano. Alcuni usi possono essere uno studente E insegnare anche altre classi. Devono avere accesso agli studenti delle loro classi E agli studenti delle classi che insegnano.

Idealmente, voglio implementarlo come due funzioni: una per ruolo e poi "unione" se un utente ha più ruoli.

La mia domanda è: quale modello dovrei usare per implementarlo?

Esternamente

  • Devo dividere la mia API per ruolo? GET /teacher/studentse GET /student/studentsnon mi sembra giusto.
  • Tieni tutto ciò che sono una risorsa (preferita)

Internamente

Come dovrebbe essere implementato internamente?

  • Ogni metodo dovrebbe iniziare con un interruttore BIG / se per ruolo?
  • Devo implementare un repository per ruolo?
  • Esiste un modello di progettazione che mi aiuterà a raggiungere questo obiettivo?

Come commento laterale: sto usando l' API Web ASP.NET e Entity Framework 6 , ma non importa davvero per l'implementazione concettuale.


3
"questa è un'ottima domanda, vorrei sapere se sei arrivato con una soluzione per questo, perché sto cercando di fare qualcosa di simile. Quello che penso dovrebbe essere: Innanzitutto, implementeremo un API che restituisce tutti i dati necessari , quindi ogni client si connetterà non direttamente all'API ma a un proxy che sarà responsabile del filtro dei dati in base ai ruoli di quell'utente "
Cleiton,

Risposte:


11

È necessario progettare l'API in base alle risorse, non in base ai ruoli, ad esempio:

/rest/students

dovrebbe essere accessibile a chiunque abbia un ruolo che gli consenta di vedere gli studenti.

Internamente, stai implementando la sicurezza basata sui ruoli. Il modo in cui lo fai dipende dai dettagli della tua applicazione, ma supponiamo che tu abbia una tabella dei ruoli, ogni persona ha uno o più ruoli e quei ruoli determinano ciò a cui ogni persona può accedere. Hai già dichiarato le regole per l'accesso agli studenti:

  • gli studenti possono accedere agli studenti nelle classi che frequentano
  • gli insegnanti possono accedere agli studenti nelle classi che insegnano

Quindi quando una persona chiama:

/rest/students

tu chiami un metodo che accede agli studenti, passando nel ruolo della persona. Ecco qualche pseudo codice:

roles = person.roles; //array
students = getStudents( roles );
return students;

e in quel metodo, potresti ottenere gli studenti per ogni ruolo con chiamate separate, ad esempio:

factory = getFactory();
classes= [];
students = [];
for( role in roles ){
    service = factory.getService( role );
    // implementation details of how you get classes for student/teacher are hidden in the service
    classes = classes.merge( service.getClasses( person ) );
    // classes[] has class.students[]
    // loop on classes and add each student to students, or send back classes with nested students? depends on use case
  }
}

Questa è un'idea molto approssimativa per quello che potresti fare e non si adatta necessariamente alle tue esigenze specifiche, ma dovrebbe darti un'idea dei pezzi coinvolti. Se vuoi restituire le lezioni con ogni studente elencato, questo è un buon approccio. Se vuoi solo gli studenti, puoi estrarli da ogni classe e unirli in una raccolta di studenti.

No, non dovresti avere un repository separato per ruolo. Tutto il ruolo che fa è determinare come ottenere i dati e forse cosa si può fare con i dati (es. Gli insegnanti possono inserire i voti degli studenti). I dati stessi sono gli stessi.

Per quanto riguarda i pattern, questo approccio utilizza Factory Pattern per sottrarre il servizio che ottiene i dati in base al ruolo. Potrebbe essere o non essere appropriato disporre di servizi separati per ruolo. Mi piace questo approccio perché minimizza la quantità di codice in ogni fase del programma e lo rende più leggibile di un interruttore o di un blocco.


1
Grazie per la risposta. Ho finito per fare qualcosa di simile a quello che mi hai suggerito. Usando LINQ2SQL (C #) ho potuto passare la query a ciascun "ruolo" e applicare un dove per ogni ruolo ottenuto dall'utente. Il risultato sarebbe un'istruzione sql con una condizione "OR" per ogni ruolo a cui l'utente ha accesso. Se non viene assegnato alcun ruolo a un utente, restituisco semplicemente Enumarable.Empty () al chiamante.
Casper Jensen,

0

Trova una penna e un foglio e inizia a modellare il tuo sistema.

Scoprirai che probabilmente hai bisogno di un'entità di dominio chiamata PERSON. Poiché sia ​​STUDENTI che INSEGNANTE "è una" PERSONA, potresti creare un'entità astratta chiamata PERSON con attributi generici come nome, cognome, ecc. UN INSEGNANTE -> è-a -> Persona. Ora puoi provare a trovare le caratteristiche di un INSEGNANTE che non si applica agli STUDENTI; es. UN INSEGNANTE insegna CLASSE a uno o più SOGGETTI.

L'applicazione della sicurezza è considerata un aspetto non funzionale dell'applicazione. Si tratta di una preoccupazione trasversale che dovrebbe essere gestita al di fuori della "logica aziendale". Come sottolinea @Robert Munn, i RUOLI dovrebbero essere mantenuti tutti in un unico posto. L'uso dei ruoli per limitare l'accesso a determinate funzioni è piuttosto approssimativo e il concetto è chiamato controllo degli accessi in base al ruolo (RBAC).

Per verificare se un insegnante dovrebbe essere autorizzato a vedere i voti degli studenti, deve essere espresso nel modello del tuo dominio. Supponiamo che un insegnante abbia una lezione sulla programmazione della materia. Probabilmente esprimeresti nel tuo modello che gli studenti frequentano le lezioni per diverse materie. È qui che entra in gioco la logica dell'applicazione / business. Questa è la logica che è possibile verificare utilizzando lo sviluppo test-driven.

È necessario dividere le risorse per rendere l'applicazione testabile e modulare.

Ad ogni modo, il modo migliore per mostrare veramente cosa intendo è mostrarlo con il codice :) Ecco una pagina GitHub: https://github.com/thomasandersen77/role-based-rest-api

In bocca al lupo :)


3
il tuo link è andato ...
Cleiton,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.