Accendo > Publikované > ASPX Úvod do ochrany – 03 CustomRoleManager

Autor:                  Libor Bešenyi

Dátum:                2012/07/20

Zmena:                                2012/07/20

CustomRoleManager

V predchádzajúcom diely sme si ukázali aké jednoduché je naimplementovať bezpečnostný model do naších stránok z .Netu. Tam sme ale narazili na problém autorizácie. Vo väčšine prípadov nestačí, aby sme užívateľa len overili, ale potrebujeme mu priradiť nejaké práva.

V kombinácii so security modelom z .Netu vieme použiť ďalší komponent. Volá sa RoleManager. Microsoft ponúka nejaké defaultne manažéry, ale väčšinou je to nepoužiteľné – hlavne ak každý systém má inú správu práv. Napr. u nás existuje úplne oddelená interná aplikácia definujúca a riadiaca užívateľov. Je to kvôli tomu, že naší užívatelia musia získavať nejaké akreditácie a naša firma ich môže udeľovať. Správa akreditácii ale nie je jednoduchá a podlieha v našom prípade legislatíve (G2B).

Takže namiesto znásilňovania existujúcich manažérov sme sa rozhodli napísať si vlastný. Je to veľmi jednoduché. Najprv si votvoríme triedy odvodenu od RoleProvidera. Metódy, pri metódach, ktoré nepotrebujeme raisneme výnimku a v prípade potreby sa doimplementujú. Zaujímava teda ostáva metóda GetRolesForUser(). V nej priradíme roly k užívateľovi (LoginName). Môžeme to ťahať cez SOAP alebo z DB. V našom prípade to budeme ťahať z nejakej staticek štruktúry – ktorú používame z minulých častí.

internal static readonly Dictionary<string, Tuple<string, MyRole>> Uzivatelia = new Dictionary<string, Tuple<string, MyRole>>()

{

       { "uzivatel", new Tuple<string, MyRole>("heslo", MyRole.User) },

       { "manazer", new Tuple<string, MyRole>("heslo", MyRole.User | MyRole.Manager) },

       { "admin", new Tuple<string, MyRole>("admin", MyRole.Admin) },

};

 

Takže máme užívateľské meno a potom „detail“ o užívateľovi (keďže sa mi lenilo to robiť cez DB). V tom detaile je zadefinované heslo a roly. V príklade používam roly ako enumeráciu a rozhodol som sa, že ich budem vedieť kombinovať.


public enum MyRole

{

       Admin = 1,

       User = 2,

       Manager = 4

} // public enum MyRole

 

Všetko ale záleží na požiadavkách. Môžeme si povedať, že každý užívateľ bude patriť práve jednej role. V príklade však definujem užívateľa, ktorý patrí len do jednej roly, manažéra (ktorý má zároveň práva užívateľa) a admina, ktorý má všetky roly. Kombinácia rolý nám umožňuje definovanie skupín (aj keď na to sa môžu použiť iné nástroje .Netu). Napríklad hromadne viem povoliť moduly pre užívateľa a automaticky tieto moduly budú povolené pre manažéra. Ku modulom, kde priradím len manažéra užívateľ ale prístup mať nebude. V takejto politike sa ale vieme zamotať, takže to treba používať triezvo a len v jednoduchých systémoch.

Takže takto bude vyzerať metóda nášho RoleManagera:

public override string[] GetRolesForUser(string username)

{

       if (!WebFormLogin.Uzivatelia.ContainsKey(username))

             throw new NotSupportedException();

 

       bool jeAdmin = (username == "admin");

       var definiciaUzivatela = WebFormLogin.Uzivatelia[username];

 

       // Prejdeme roly a ak su definovane pre dane konto, tak ich priradime

       var roly = new List<string>();

       foreach (MyRole aktualnaRola in Enum.GetValues(typeof(MyRole)))

       {

             if ((definiciaUzivatela.Item2 & aktualnaRola) == aktualnaRola || jeAdmin)

                    roly.Add(aktualnaRola.ToString());

       } // foreach

 

       return roly.ToArray();

}

 

Aplikácii musíme teraz povedať, že na správu rolý sa má použiť náš provider. To sa nastavuje vo web.configu:

<roleManager enabled="true" defaultProvider="CustomProvider" cacheRolesInCookie="true" cookieProtection="All" createPersistentCookie="false">

       <providers>

             <clear />

             <add name="CustomProvider" type="WebApplication1.CustomRoleManager" />

       </providers>

</roleManager>

 

Tu sa chcem pozastaviť. Z predchádzajúcich častí vieme, že to prehliadač hovorí serveru, že (nie)je prihlásený. Ako teda server vie aké má užívateľ roly? Zakaždým si ich zistí (a teda volá tú našú metódu). V prípade, že zdrojom pre roly je DB alebo SOAP, mohlo by dochádzať k nepríjemným časovým odozvám alebo preťaženiam DB / siete. Preto vieme aj roly držať v prehliadači (cachovať) a posielať s každým requestom podobne ako security token. To sa nastavuje práve „cacheRolesInCookie“ parametrom. Bezpečnost vs. výkon musí riešiť každý individuálne.

Takže teraz vieme priradiť ku každému účtu aj roly. Ako to prepojiť s aplikáciou? Tak napríklad zakážme všetkým užívateľom hyperlink na stránkeWebForm1, ktorým sa dalo redirectovať na WebForm2:

HyperLinkWebForm2.Visible = Context.User.IsInRole(MyRole.Manager.ToString());

 

Teraz budú tento link na stránke vidieť len manažéri (a aj admin). Ak sa prihlásime ako užívateľ, hyperlink bude skrytý. Čo však, ak užívateľ (prihláseny) natvrdo naťuká v prehliadači url na WebForm2? Modul je povolený... Na to, aby sme ho aj „fyzicky“ zakázali, potrebujeme o tom povedať totiž aj IIS (ako sme si to vysvetlili v predchádzajúcej časti). RoleManager sa prepája s authorizáciou kde vieme povoľovať alebo zakazovať roly (oddelené čiarkou) „z hora nadol“. Teda vieme napr. všetky stránky zakázať (location /) a potom pridávať povoľujúce výnimky. V našom prípade proste module WebForm2 zakážeme User role:

<location path="WebForm2.aspx">

       <system.web>

             <authorization>

                    <deny roles="User" />

             </authorization>

       </system.web>

</location>

 

Tu vydno nevýhodu systému. Generovanie kódu musí byť manuálne riadené a práva na formuláre tiež (kde môže vznikať duplicita). No zasa to až taká katastrofa nie je a zmenu pravidiel si človek všimne hneď, keď aplikáciu spustí a modul ho redirektuje na login obrazovku.

Demonštračný projekt na stiahnutie: www.accendo.sk/Download/AspxOchranaDemo03.zip