tanketorsken.dk/bitmasking-for-begyndere-af-en-begynder/

Feeds

Bitmasking for begyndere af en begynder

Er igang med mit første asp.net projekt hvor jeg har valgt at bruge den indbyggede Membership/Roles – funktionalitet. Jeg har dog brug for at kunne lave adgangsregler på et mere detaljeret plan end på sideniveau, og har derfor lavet en lille Authorization-klasse der klarer dette. I en static Globals klasse er der defineret to Enumerations:

[Flags]
private enum Roles
{
    Administrator = 1,
    Editor = 2,
    Member = 4,
    ThirdParty = 8,
    All = Administrator | Editor | Member | ThirdParty
}
 
[Flags]
public enum Actions
{
    Frontpage = Roles.All,
    Articles_PostComment = Roles.Administrator | Roles.Member,
    Jobs_List = Roles.Administrator | Roles.Editor | Roles.Member,
    Jobs_Create = Roles.Administrator | Roles.Editor
}

I Authorization-klassen udregner jeg brugerens værdi ved at lægge værdierne for brugerens roller sammen:

private int GetUserValue()
{
    int sum = 0;
    
    foreach(string role in Roles.GetRolesForUser())
    {
        sum += (int)Enum.Parse(typeof(Globals.Roles), role);
    }
    
    return sum;
}

Da de forskellige Roles har værdier der alle er potenser af 2, kan jeg let lave en Authorization.IsAllowed() funktion der ved hjælp af bitmasking tjekker om en bruger har den ønskede rolle:


// userRoleValue er den returnerede værdi af
// Authorization.GetUserValue()
 
public bool IsAllowed(Globals.Actions allowedRoleLevel)
{
    return (((int)allowedRoleLevel & userRoleValue) != 0);
}

Og hvad er bitmasking så?
I bitmasking udfører man operationer på et tals binære repræsentation. I mit tilfælde brugte jeg de to bitwise-operators AND & og OR | der fungerer som følger:

// AND sammenligner to binære repræsentationer
// af samme længde og for hvert bitpar er
// resultatet 1 hvis den første bit er 1 OG
// den anden bit er 1
 
    010011
AND 111001
    010001
 
// OR sammenligner to binære repræsentationer
// af samme længde og for hvert bitpar er
// resultatet 1 hvis den første bit er 1 ELLER
// den anden bit er 1 (eller begge bits er 1)
 
   010011
OR 111001
   111011

Ved at kigge på mit konkrete eksempel, kan det ses hvordan bitmasking fungerer:


// De forskellige værdier for Roles er i binær repræsentation:
 
Administrator = 0001
Editor = 0010
Member = 0100
ThirdParty = 1000
 
// I Globals.Roles kombineres flere a disse roller
// ved OR operatoren |
// Resultatet af f.eks Administrator | Member bliver:
 
   0001
OR 0100
   0101

Her ses vigtigheden af at alle værdier er potenser af 2. Ved at benytte OR operatoren kan flere rollers status gemmes i et tal. Når man skal gå den anden vej og tjekke om en rolle har adgang til en action benyttes AND operatoren:


// For en action er følgende rettigheder defineret:
Article_Create = Administrator | Editor // 0011
 
// En bruger (anders) har rolerne Member og ThirdParty
// og vi vil nu undersøge om han har rettighed til at
// udføre Article_Create.
// Brugerens værdi er udregnet som:
 
anders = Member | ThirdParty // 1100
 
// Ved at benytte AND operatoren på brugerens værdi (1100)
// og værdien for den pågældende action (0011) og se om
// resultatet er forskellig fra 0 har vi praksis svaret
// på spørgsmålet:
 
((anders & Article_Create) != 0) // Boolean svar på om anders må udføre Article_Create