Sicurezza a livello di riga con più regole

0

Ho bisogno di assistenza per la progettazione di un sistema che implementa la sicurezza a livello di riga che potrebbe avere più condizioni che devono essere soddisfatte.

Contesto

Supponiamo di avere un utente. Un utente può appartenere a 1 ... n organizzazioni, 1 ... n reparti e 1 ... n posizioni. Forse correlati / utili: Queste tabelle seguono un flusso gerarchico in cui i dipartimenti appartengono a 1 ... n organizzazioni e le posizioni appartengono a 1 ... n reparti.

Il mio caso d'uso

Supponiamo di avere un'entità documento. Solo i gruppi di utenti che soddisfano la regola di visibilità associata per questo documento possono accedervi.

Esempi (gli elenchi rientrati sono possibili esempi di restringimento della regola definita per il documento)

  • solo utenti nell'organizzazione X.
    • nell'organizzazione X, dipartimento 1
    • nell'organizzazione X, reparto 1, posizione A
    • nell'organizzazione X, posizione A
  • solo utenti nel dipartimento 1
    • nel reparto 1, posizione A
  • solo utenti in Posizione A

Un documento avrà un elenco di queste regole. Pertanto qualsiasi combinazione di quanto sopra è possibile, ma fino a quando come è soddisfatta qualsiasi regola, quindi l'utente ha accesso.

La mia attuale implementazione include la creazione di questa tabella che include la creazione di queste regole in cui le 3 categorie sono campi nullable / facoltativi.

Nell'esempio seguente, supponiamo di avere un documento con Id 1. Quindi "solo gli utenti nell'organizzazione X" avrebbero una riga che assomigliava a {ID Documento: 1, Organizzazione X}. Un altro esempio "nell'organizzazione X, posizione A" sarebbe simile a {ID Documento: 1, Posizione A, Organizzazione X}

Per controllare l'accesso, dovrei prendere una lista di regole per il documento specificato. Se una regola ha tutte e tre le proprietà specificate, l'utente deve appartenere a tutte e tre le proprietà. Ma questo diventa più complesso perché un documento può avere più regole con l'unica condizione che l'utente deve soddisfare una di queste regole. Quindi lo stesso documento potrebbe avere una regola in cui viene specificata solo una proprietà. Questa implementazione genera un sacco di se dichiarazioni

Come potrei fare per implementare questo design in modo più pulito? TIA.

    
posta alexhuang 07.07.2016 - 16:46
fonte

1 risposta

0

Penso che stai andando nella giusta direzione. Non sono sicuro che utilizzerei campi nullable / opzionali però. Nella mia mente, NULL significa "sconosciuto", non "ANY".

Utilizzando i dati di esempio è possibile creare una tabella

DocID    Org    Dept    Posn
  1       X      1       any
  1       X      1        A     // redundant, due to the record above
  1       X     any       A
  1      any     1        A
  1      any    any       A

Per ogni utente dato, il test sarebbe

select count(*) from DocPerms
where DocID = @docID
    and (Org = @myOrg or Org = 'any')
    and (Dept = @myDept or Dept = 'any')
    and (Posn = @myPosn or Posn = 'any')

Se quel conteggio è maggiore di zero, l'utente ha accesso.

Si noti che non dobbiamo necessariamente farlo in SQL. Potresti voler farlo in codice invece:

(Secondo il tuo commento, ora si presume che l'utente possa trovarsi in più di un org / dept / posn, mentre il codice sopra suppone che l'utente si trovi esattamente in uno)

var docRules = allDocRules.where(e => e.DocID == docID);  // get the set of rules for this document

var firstApplicableRule = docRules.FirstOrDefault(e => MatchRules(user, e));

bool userhasAccess = (firstApplicableRule != null);
....

private bool MatchRules(Person u, Rule r)
{
    // return true if any of u's roles apply to the specific rule
    bool result = false;
    foreach (Role theRole in u.Roles) 
    {
         if ((theRole.Org == r.Org || r.Org == "any")
            and (theRule.Dept == r.Dept || r.Dept == "any")
            and (theRule.Posn == r.Posn || r.Posn == "any"))
         {
             result = true;
             break;
         }
    }
    return result;
}

Se lo fai nel codice, puoi aggiungere Booleans per i campi "qualsiasi":

r.IsDeptWildCard

Se stai facendo questo nel database, puoi usare un valore fuori limite (-1) o un link a uno speciale "qualsiasi" record (non il miglior design, sono sicuro che qualcuno ne proporrà uno migliore )

    
risposta data 07.07.2016 - 17:07
fonte