Dziś bardzo przyjemny temat związany z tym jak szybko zaimplementować względnie prosty mechanizm autoryzacji, zarządzania użytkownikami, rolami i poziomami dostępu. Oczywiście w ASP.NET i C# :) Postaram się omówić zagadnienie od początku, tak by użycie przez osobę, dla której to nowość nie stanowiło jakiegoś specjalnego wyzwania.

Wstęp

Zacznijmy od ustalenia co należałoby zrobić aby dodać zarządzanie użytkownikami do własnej witryny. Oczywiście należy dodać tabelki do bazy (na dobrą sprawę 3 – dla użytkowników, ról oraz przyporządkowań user-role), potem dodać jakiś mechanizm dodawania ról, użytkowników i przypisywania ich do ról (dla administratora – po to by nie robić tego bezpośrednio w bazie, choć oczywiście się da). Następnie przydałby się mechanizm do edycji tych danych przez samego użytkownika (np. zmiana hasła, danych, e-maila, itd); możemy także wymagać by użytkownik, zmieniając hasło, wybrał bezpieczne hasło (ok, nie ma bezpiecznych haseł, są tylko łatwe i trudniejsze do złamania :)), dodatkowo chcielibyśmy, żeby hasło można było przypomnieć przez mejla… albo wygenerować nowe. Jeszcze byłoby fajnie gdyby ograniczyć ilość prób zalogowania się do, powiedzmy, 5 i po tych kilku próbach poczekać ok 10 min, żeby spróbować ponownie. I trochę więcej.

Widać, że temat prosty, ale nagle się rozbudował. I gdyby nie Membership Provider należałoby taką funkcjonalność zrobić absolutnie samemu. Jest to oczywiście fajne, itd. Ale może się okazać bolesne w projekcie składającym się także z wielu innych rzeczy :) Można zamiast tego użyć jedną z gotowych implementacji aby mieć funkcjonujący moduł dostępu w kilkanaście minut o wszystkich tych funkcjonalnościach.

No właśnie – Membership Provider dostarcza kilka gotowych implementacji:

  • ActiveDirectoryMembershipProvider – czyli gotowe wykorzystanie Active Directory (jeśli tylko je posiadamy i chcemy w ogóle użyć)
  • SqlMembershipProvider – to co nas najbardziej interesuje, czyli wykorzystanie własnej bazy danych do zarządzania użytkownikami. Ograniczone jest tylko do Sql Servera, jednak można to bez większych problemów ominąć.

Ewentualnie możemy napisać własnego Membership Providera, nadpisując tylko wybrane metody – dzięki temu możliwa jest obsługa innych baz danych, ale trzeba poświęcić na to trochę więcej czasu – i samemu porobić odpowiednie tabelki, itd.

Przygotowanie

Wiemy już z czym to się je. Teraz czas na rozpoczęcie z tym pracy. Pierwsza rzecz jaką należy zrobić to przygotowanie tabelek. Można to zrobić w sposób dwojaki. Pierwszy – wykorzystując programik aspnet_regsql.exe. Jest to taki kreator, gdzie można stworzyć tabele do UserManagement, ProfileManagement i RoleManagement. Nam wystarczy tylko zarządzanie użytkownikami i rolami. Jest też opcja nr. dwa – otworzyć sobie katalog z .NET Framework 2.0 (u mnie jest to: C:\Windows\Microsoft.NET\Framework\v2.0.50727\ ) i odpalić w SQL 3 skrypty: InstallCommon.sql, InstallMembership.sql oraz InstallRoles.sql.

Po utworzeniu tabel można je jeszcze trochę dostosować do naszych potrzeb. Przez dostosowanie rozumiem dodanie dodatkowych kolumn do User (nie zalecam nic usuwać, chyba, że w sposób przemyślany i z uwzględnieniem procedurek, które też trzeba byłoby poprawić). Warto dodać kolumnę id_user INT, która będzie nam łączyła rozwiązanie Membership Providera z resztą naszej aplikacji. Mało bowiem ciekawie łączy się różne tabele po Guid. Nawiasem mówiąc ciekawe jest z jakiego powodu Guid jest używany jako standardowe pole z Primary Key do łączenia tabel.

Po utworzeniu tabel widzimy coś takiego:

image

No ok, teraz wypadałoby troszkę uzupełnić dane w tych tabelach by można było to zaraz przetestować. Można to zrobić znowu – w dwojaki sposób: albo przez dodawanie danych w SQL, ale to ze względu na Guidy może być mało przyjemne lub za pomocą pewnego toola. Dokładniej chodzi o Web Site Admin Tool. Tylko zanim się za niego weźmiemy musimy sprawdzić czy w naszym projekcie, który używa / będzie używał Membership Providera ścieżka dostępu nie zawiera żadnych znaków specjalnych. Tak. Niestety jest to znany i nierozwiązywalny bug (link w referencjach). Jeśli więc nasza solucja znajduje się w katalogu D:\Projekty\C#\MembershipProvider to będziemy widzieli błędy: Timeout Exception lub błąd typu błąd. Najlepiej skopiować solucję w “bezpieczne miejsce” i dopiero taką solucję należy otworzyć przez Visual Studio. W Visual Studio w Solution Explorerze jest widoczna ikonka ustawień ASP.NET. Klikamy w nią aby uruchomić Web Site Admin Toola.

Skończyliśmy się bawić z toolami i bazą – teraz zajmiemy się web.configiem i konfiguracją Membership Providera w naszej aplikacji.

Konfiguracja

W sekcji configuration w web.config należy dodać ConnectionString do połączenia z bazą zawierającą nasze tabele Membership Providera, a poza tym 3 sekcje: authentication, membership i roleManager. Nie wspominałem jeszcze tylko o authentication – służy ono do prawie automatycznej autoryzacji na formularzach, ale nie tylko. Jako przykład zamieszczę swoją template-ową konfigurację:

<!-- Authentication methods -->  
<authentication mode="Forms">  
    <forms loginUrl="~/Account/LogOn" 
        timeout="2880" 
        protection="All" 
        name="AppNameCookie" 
        enableCrossAppRedirects="false" />
</authentication>  
<!-- Users Management -->  
<membership defaultProvider="CustomSqlMembershipProvider" userIsOnlineTimeWindow="15">  
    <providers> 
        <clear/> 
        <add name="CustomSqlMembershipProvider" 
            type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" 
            connectionStringName="DefaultConnection" 
            enablePasswordRetrieval="false" 
            enablePasswordReset="true" 
            requiresQuestionAndAnswer="false" 
            requiresUniqueEmail="true" 
            passwordFormat="Hashed" 
            maxInvalidPasswordAttempts="5" 
            minRequiredPasswordLength="6" 
            minRequiredNonalphanumericCharacters="0" 
            passwordAttemptWindow="10" 
            passwordStrengthRegularExpression="" 
            applicationName="/" /> 
    </providers> 
</membership>  
<!-- Role Management -->  
<roleManager enabled="true" defaultProvider="CustomSqlRoleProvider">  
    <providers> 
        <clear/> 
        <add connectionStringName="DefaultConnection" 
            applicationName="/" 
            name="CustomSqlRoleProvider" 
            type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
        <add applicationName="/" 
            name="CustomRoleProvider" 
            type="System.Web.Security.WindowsTokenRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> 
    </providers> 
</roleManager>  

Widzimy tu większość ustawień, o których wcześniej wspominałem – wszystko ładnie w jednym miejscu :)

Nieźle długi post z tego wyszedł, więc podzielę go na dwie części. Część wprowadzająca za nami, natomiast wykorzystanie w naszej przykładowej stronie internetowej – już niedługo. Nie obiecuję konkretnego terminu, ale postaram się napisać i wrzucić na bloga dość szybko Uśmiech

Referencje

Microsoft Connect - bug z Web Site Admin Tool

Przegląd informacji na temat Web Site Admin Tool

How To: Use Forms Authentication with SQL Server in ASP.NET 2.0

Przykładowa implementacja Role-Provider

How To: Use Membership in ASP.NET 2.0