18.July 2008 12:04Bitmasking 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