I tentokrát se podíváme na další novinky v novém .NET, konkrétně postupy okolo přihlašování a správy uživatelů. V tomto článku se zaměřím spíše na tu praktickou část, abyste mohli co nejdříve začít vytvářet aplikace.

Správa uživatelů v novém .NETu je založena na takzvaném Provider modelu. Díky tomu není potřeba pro základní operace s uživateli psát jakýkoli kód. Přihlašování nebo registrování uživatelů můžete zprovoznit pouze pomocí drag-dropu několika prvků. Přidat do stránky rámeček pro přihlašování uživatelů je nyní stejně jednoduché jako vložit do stránky třeba Label.

Framework .NET 2.0 je dodáván se dvěma základními poskytovateli – AccessMembershipProvider a SqlMembershipProvider. Nyní bych řekl něco málo ke každému z nich. Základní rozdíl je myslím jasný. Prvek SqlMembershipProvider používá jako datový zdroj MS SQL databázi, zatímco AccessMembershipProvider uchovává uživatele v Accessu.

Pro větší názornost jsem připravil zdrojové kódy ukázek, které si můžete stáhnout a vyzkoušet.

AccessMembershipProvider

Aby začal tento provider „pracovat“ stačí zpřístupnit formulářovou autentizaci:

<authentication mode=”Forms” />

Spokojíte-li se s defaultním nastavením, tento provider se postará prakticky o všechno. Vytvoří si dokonce i potřebné databázové objekty. Na vás zůstává pouze „natáhnout“ do stránky ovládací prvky pracující s uživatelskými účty. Základní chování však nemusí vždy vyhovovat, proto máme možnost modifikovat chování provideru podle našich představ:

<membership defaultProvider=“AccessProvider“ userIsOnlineTimeWindow=“15″>
 <providers>
  <clear />
  <add
   name=“AccessProvider“
   type=“System.Web.Security.AccessMembershipProvider“
   connectionStringName=“MyAccessConnString“
   applicationName=“firstApp“
   enablePasswordRetrieval=“false“
   enablePasswordReset=“true“
   requiresQuestionAndAnswer=“true“
   requiresUniqueEmail=“true“
   passwordFormat=“Hashed“ />
 </providers>
</membership>

Pomocí atributu name nastavíte název providera. Tento název použijete na prvním řádku ukázky:

<membership defaultProvider=“AccessProvider“ . . . >

Atribut type říká aplikaci, kde má hledat třídu providera. V .NET Frameworku můžete najít (zatím) dva, System.Web.Security.AccessMembershipProvider a System.Web.Security.SqlMembershipProvider. Nic vám však nebrání napsat svůj vlastní provider. Mně například chybí provider pro XML soubory.

Atribut ConnectionStringName pouze ukazuje na připojovací řetězec k databázi, uložený v sekci connectionStrings v souboru web.config:

<connectionStrings>
 <add name=“MyAccessConnString“ connectionString=“. . .“ />
</connectionStrings>

Atribut ApplicationName se hodí, hostujete-li více aplikací na jednom webserveru. Tímto atributem zajistíte odlišení uživatelů příslušících k jednotlivým aplikacím.

Nastavíte-li enablePasswordRetrieval na true, bude mít zapomětlivý uživatel možnost nechat si poslat ztracené heslo. Je-li však atribut passwordFormat nastaven na Hashed, nebudou uživatelé ze zřejmých důvodů schopni obdržet heslo z databáze.

Podobné je to s enablePasswordReset. Tato vlastnost se ovšem nijak nekryje s vlastností passwordFormat. Atribut enablePasswordReset jednoduše umožňuje (respektive znemožňuje) uživatelům, aby si nechali na e-mail poslat nové, náhodně generované heslo. Můj názor je ten, že je rozumnější nastavit enablePasswordRetrieval na false a enablePasswordReset na true. Chcete-li hesla hešovat, myslím, že je toto jediná rozumná varianta.

Atribut RequiresQuestionAndAnswer řeší oblast bezpečnostních otázek, požaduje-li uživatel poslání hesla na e-mail, respektive jeho resetování.

Je-li requiresUniqueEmail nastaveno na true, bude aplikace požadovat, aby se v databázi nevyskytli dva uživatelé se stejným e-mailem.

Atribut PasswordFormat může nabývat tří hodnot, Clear, Encrypted a Hashed. Všechny tři způsoby uchování hesel jsem popsal v článku Salted hash – další krok ke zvýšení bezpečnosti. Pro úplnost doplním, že možnost hashed ve skutečnosti používá hash se saltem.

SqlMembershipProvider

S poskytovatelem pro MS SQL vám v činnosti přibude ještě jeden krok navíc, nicméně u větších aplikací se s Accessem těžko spokojíme. Na rozdíl od providera pro Access, SqlMembershipProvider za vás potřebné databázové objekty nevytvoří. Tato operace je na vás. Tolik práce to zase ale není, s frameworkem je dodáván nástroj (aspnet_regsql), který stačí spustit z příkazového řádku, a ten vám s tím pomůže. Pro úplnost ještě doplním ukázku ze souboru web.config pro MS SQL providera:

<membership defaultProvider=“SqlProvider“ userIsOnlineTimeWindow=“15″>
 <providers>
  <clear />
  <add
   name=“SqlProvider“
   type=“System.Web.Security.SqlMembershipProvider“
   connectionStringName=“sqlConnString“   applicationName=“firstApp“
   enablePasswordRetrieval=“false“
   enablePasswordReset=“true“
   requiresQuestionAndAnswer=“true“
   requiresUniqueEmail=“true“
   passwordFormat=“Hashed“ />
 </providers>
</membership>

Login Controls

Když už aplikace ví, jak si přejeme, aby s uživatelskými účty pracovala, můžeme začít tvořit stránky. Ke správě uživatelů slouží takzvané Login Controls. Nyní si postupně ukážeme ty nejzajímavější.

CreateUserWizard

Abychom vůbec měli v aplikaci nějaké uživatele, musíme je nejdříve vytvořit. K tomu nám velmi dobře poslouží, jak už sám název napovídá, CreateUserWizard. Tento prvek (stejně jako některé další) se vykreslí přesně podle nastavení, která jsme zanechali v souboru web.config v sekci <membership />. Pokud tedy v našem příkladu máme nastaveno requiresQuestionAndAnswer na true, zobrazí tento prvek textová pole pro bezpečnostní otázku a odpověď. Stejným způsobem se chovají i další prvky, ke kterým se ještě dostaneme.

<asp:CreateUserWizard ID=“createUser“ runat=“server“ />

Tento zápis přidá do stránky prvek, který se postará o registrování nových uživatelů. Nemusíte psát žádné obslužné metody událostí, postará se opravdu úplně o všechno.

Prvek CreateUserWizard

Možná by ale bylo dobré trochu poupravit vzhled a asi také přeložit popisky (máme to přeci jen o něco složitější než Angličané). O vzhled se můžete postarat způsobem, na jaký jste v .NETu zvyklí. Ostatně o popisky také. Máte-li například Visual WebDeveloper, najdete si vlastnosti řešící tuto problematiku celkem snadno, v opačném případě vás odkážu na dokumentaci, kde je vše vyčerpávajícím způsobem popsáno. Nicméně, pokud vám předvedu prvních pár vlastností, které jsou nositeli textů v popiscích, věřím, že ostatní už hravě odhadnete, takže: UserNameLabelText, PasswordLabelText, ConfirmPasswordLabelText

Zmíním ovšem ještě jinou vlastnost, která se mi zdá užitečná. Bude-li AutoGeneratePassword rovno true, neobjeví se v boxu položky Password a Confirm Password a heslo bude náhodně generováno a odesláno na uživatelův e-mail. K tomu budeme ale muset ještě něco málo přidat do prvku CreateUserWizard:

<asp:CreateUserWizard ID=“CreateUser“ runat=“server“ >
 <MailDefinition BodyFileName=“~/userregmail.txt“
  From=“vas @ server.cz“
  Subject=“Potvrzeni registrace“ />
</asp:CreateUserWizard>

Ve vlastnosti BodyFileName definujeme umístění textového souboru s tělem e-mailu. Uvnitř tohoto souboru můžete používat výrazy typu <% UserName %> či <% Password %>, abyste byli schopni uživateli sdělit jeho nacionále. Tento scénář se také může hodit, abyste měli jistotu, že e-mail, který uživatel zadal, je platný. Konfigurace odesílání e-mailu podléhá nastavení sekce smtpMail v souboru web.config.

Login Control

Nyní bychom měli vytvořit rozhraní pro logování již existujících uživatelů. O to se postará prvek Login. Podobně jako CreateUserWizard, ani Login nepotřebuje ke své činnosti nic víc, než vložit do stránky:

<asp:Login ID=“Login“ runat=“server“ />

Tento zápis bude mít za následek zhruba tento výstup:

Prvek Login

Vzhled opět nevalný, ale s tím si teď lámat hlavu nebudeme. Asi by ale opět bylo vhodné změnit UserNameLabelText a PasswordLabelText na české hodnoty. Tady však chci, kromě již zmiňovaných UserNameLabelText a PasswordLabelText, poukázat na existenci několika dalších vlastností:

  • CreateUserText a CreateUserUrl – text a odkaz na stránku, která zařídí registraci nového uživatele.
  • DisplayRememberMe – určuje, má-li se zobrazit CheckBox „remember me“.
  • RememberMeSet – defaultní stav CheckBoxu „remember me“.
  • RememberMeText – popisek u ChceckBoxu „remember me“.
  • FailureText – zpráva, která se zobrazí po neúspěšném pokusu o ověření identity uživatele.
  • PasswordRecoveryText a PasswordRecoveryUrl – odkaz, který se postará o uživatele, ztratí-li své heslo. Za tímto odkazem by se měl skrývat prvek PasswordRecovery.
  • VisibleWhenLoggedIn – umožňuje skrýt box po přihlášení uživatele.

PasswordRecovery Control

Tento prvek umožní uživatelům získat zpět, respektive generovat nové heslo. Základní chování opět závisí na nastavení providera v souboru web.config. Máte-li nastaveno hashování hesel, těžko mu asi aplikace pošle heslo, ale spíše vygeneruje nové. Hesla jsou odesílána na uživatelův e-mail a stejně jako u prvku CreateUserWizard musíme nejdřív definovat vlastnosti tohoto e-mailu. Rovnou uvedu ukázku, po zkušenostech s předchozími prvky bude vše jasné:

<asp:PasswordRecovery ID=“PasswordRecovery“ runat=“server“>
 <MailDefinition BodyFileName=“~/passwordremind.txt“
  From=“vas@server.cz“
  Subject=“Ztracene heslo“ />
</asp:PasswordRecovery>

Prvek PasswordRecovery - dotaz na uživatelské jméno

Po vložení platného uživatelského jména se zobrazí bezpečností otázka, kterou zadal uživatel při registraci:

Prvek PasswordRecovery - ověření uživatele bezpečnostní otázkou

ChangePassword Control

Co se týče funkce tohoto prvku, není zde, myslím, co vysvětlovat. Před samotnou změnou hesla se aplikace klasicky „zeptá“ na heslo aktuální, poté dvakrát na nové. Stejně jako již zmiňované prvky PasswordRecovery a CreateUserWizard, obsahuje i tento vlastnost MailDefinition:

<asp:ChangePassword ID=“ChangePass“ runat=“server“>
 <MailDefinition BodyFileName=“~/changepass.txt“
  From=“vas@server.cz“
  Subject=“Zmenene heslo“ />
</asp:ChangePassword>

Prvek ChangePassword

LoginStatus a LoginName

Tyto dva prvky se většinou používají společně. Společně také bývají popisovány a ani já tento trend nenaruším. Prvek LoginName zobrazuje jméno přihlášeného uživatele. Není-li nikdo přihlášen, nezobrazí se nic. Prvek LoginStatus zobrazuje vždy jeden ze dvou odkazů – buď Login (je-li uživatel anonymní) nebo Logout (byl-li uživatel již přihlášen). Použijete-li tyto dva prvky společně, může se vám dostat například tohoto výstupu:

Prvek LoginName a LoginStatus

Po klepnutí na Login se stránka přesměruje na URL definované v souboru web.config, kde by nejspíš mohl čekat prvek Login, který jsme si už probrali:

<authentication mode=“Forms“>
 <forms loginUrl=“Login.aspx“>
  . . .
 </forms>
</ authentication>

Prvek LoginStatus předá přihlašovací stránce URL, ze kterého byla volána, takže po úspěšném přihlášení se uživatel opět vrátím tam, kde před tím skončil, avšak již přihlášený:

Prvek LoginName a LoginStatus po přihlášení uživatele

Je-li tedy uživatel již přihlášen, LoginStatus v našem případě zobrazí odkaz s textem „(odhlásit)“, LoginName nám ukazuje jméno přihlášeného. Kód zajišťující tuto funkcionalitu vypadá zhruba takto:

<asp:LoginName ID=“name“ runat=“server“
     FormatString=“Přihlášený uživatel: {0}“ />
<asp:LoginStatus ID=“status“ runat=“server“
     LogoutText=“(odhlásit)“ LoginText=“Login“ />

LoginView Control

Když už jsme prošli správu uživatelů, můžeme přejít k zobrazování obsahu samotným uživatelům. Abych řekl pravdu, tento prvek mě tak trochu zklamal. Prvek LoginView zobrazuje různý obsah závisející na rolích jednotlivých uživatelů, respektive na stavu uživatele – přihlášený nebo anonymní:

<asp:LoginView ID=“LoginView“ runat=“server“>
 <LoggedInTemplate>
  Obsah pro přihlášené uživatele….
 </LoggedInTemplate>
 <AnonymousTemplate>
  Chcete-li vidět to co vidí přihlášení, přihlaste se…
 </AnonymousTemplate>
</asp:LoginView>

Až do tohoto bodu s tímto prvkem žádný problém nemám. Pokračujme však dále. Již jsem zmínil, že tento prvek podporuje i zobrazení obsahu podle jednotlivých rolí. To je také pěkná myšlenka. Aplikace tedy může vypadat například takto:

<asp:LoginView ID=“LoginView“ runat=“server“>
 <RoleGroups>
  <asp:RoleGroup Roles=“Admini“>
   <ContentTemplate>
    Obsah pro administrátory…
   </ContentTemplate>
  </asp:RoleGroup>
  <asp:RoleGroup Roles=“Management“>
   <ContentTemplate>
    Obsah pro management společnosti…
   </ContentTemplate>
  </asp:RoleGroup>
 </RoleGroups>
 <LoggedInTemplate>
  Ahoj <asp:LoginName ID=“LogName“ Runat=“server“ />
 </LoggedInTemplate>
 <AnonymousTemplate>
  Prosím přihlašte se. . .
 </AnonymousTemplate>
</asp:LoginView>

Tady je však zakopán pes. Každý uživatel může vidět pouze obsah své role. Management tedy nemůže vidět to, co vidí administrátoři (chápu), ale nemůže vidět ani obsah LoggedInTemplate nebo AnonymousTemplate. Administrátorům bychom taky asi nemuseli skrývat obsah například LoggedInTemplate. Zkrátka si myslím, že existují role, které by měly mít přístup do většího počtu šablon, než jen do té své. Přiznám se, že jsem ještě toto téma nezkoumal do největších podrobností, ale myslím, že pro univerzálnější použití bude vhodné poupravit tento prvek, aby přijímal jakýsi hierarchický model rolí.

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

Žádný příspěvek v diskuzi

Odpovědět