Własne uwierzytelnianie w ASP.NET MVC 3 Razor

0

Witam
Mam do zrobienia mały projekt, który wymagał będzie panelu administracyjnego i panelu użytkowników. Ponadto chciałbym żeby administratorzy różnili się poziomem uprawnień - wszystko pięknie domyślnie jest taka możliwość. Problem tylko teraz taki, że chciałbym ilość grup użytkowników zmieniać podczas działania serwisu wraz z konkretnymi uprawnieniami no i klops.
Oryginalnie tworzy się grupy userów przez Website Administration tool - chciałbym tworzyć je manualnie, podobnie jak użytkowników i uprawnienia na konkretne akcje czyli kontrolery...
Domyślnie przed dostępem do kontrolera chronimy się w ten sposób:

[Authorize(Roles = "Administrator")]
public class StoreManagerController : Controller
{
    // Controller code here
}

a co jeśli zrobił bym dynamiczne role? na sztywno nie mogę przypisać "Księgowa" bo za tydzień taka rola może już nie istnieć a powstać nowa.
Ogólnie chciałbym dostać się do "wnętrzności" uwierzytelniania widziałem już, że jest tworzone dodatkowe połączenie z inną bazą specjalnie dla userów. Najlepiej byłoby przenieść tabele userów i autoryzacji do swojej bazy i przerobić to po swojemu.
Próbował ktoś podejść do tematu od tej strony? Może znacie jakieś ciekawe arty traktujące o tworzeniu własnej autoryzacji użytkowników w tej technologii?
Dodam jeszcze tylko, że z MVC3 i ogólnie ASP mam do czynienia od zaledwie tygodnia, w c# rzeźbie nico dłużej i rozumiem idee MVC bo pisałem conieco w CodeIgniterze.

0

Musisz dziedziczyć po klasie MembershipProvider oraz RoleProvider, zmienić config w webconfig i to w sumie tyle.

public class DziennikRoleProvider : RoleProvider
    {
        private UsersRepository repository { get; set; }

        public DziennikRoleProvider()
        {
            repository = new UsersRepository();
        }
 
        public override void AddUsersToRoles(string[] usernames, string[] roleNames)
        {
            throw new NotImplementedException();
        }

        public override string ApplicationName
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public override void CreateRole(string roleName)
        {
            throw new NotImplementedException();
        }

        public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
        {
            throw new NotImplementedException();
        }

        public override string[] FindUsersInRole(string roleName, string usernameToMatch)
        {
            throw new NotImplementedException();
        }

        public override string[] GetAllRoles()
        {
            throw new NotImplementedException();
        }

        public override string[] GetRolesForUser(string username){
              Dziennik_MVC.Models.Entities.Roles role = this.repository.GetRoleForUser(username);
            if (!this.repository.RoleExists(role))
                return new string[] { string.Empty };

            return new string[] { role.RoleName };
        }

        public override string[] GetUsersInRole(string roleName)
        {
            throw new NotImplementedException();
        }

        public override bool IsUserInRole(string username, string rolename)
        {
            Users user = repository.GetUser(username);
            Dziennik_MVC.Models.Entities.Roles role = repository.GetRole(rolename);

            if (!repository.UserExists(user))
                return false;
            if (!repository.RoleExists(role))
                return false;

            return user.Roles.RoleName == role.RoleName; ;
        }

        public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
        {
            throw new NotImplementedException();
        }

        public override bool RoleExists(string roleName)
        {
            throw new NotImplementedException();
        }
    } 

To kod z mojej klasy, możesz zaimplementować wszystkie metody.
Analogicznie Membership

 private UsersRepository repository { get; set; }

        public DziennikMembershipProvider() {
            repository = new UsersRepository();
        }

        public override int MinRequiredPasswordLength
        {
            get
            {
                return 6;
            }
        }

        public bool isUserActive(string login){
            return repository.IsActive(login);
        }

        public override bool ValidateUser(string username, string password)
        {
            if (string.IsNullOrEmpty(password.Trim()) || string.IsNullOrEmpty(username.Trim()))
                return false;
 
            string hash = FormsAuthentication.HashPasswordForStoringInConfigFile(password.Trim(), "md5");
 
            return this.repository.GetAllUsers.Any(user => (user.Login == username.Trim()) && (user.Password == hash));
        }

        public override bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            if (!ValidateUser(username, oldPassword) || string.IsNullOrEmpty(newPassword.Trim()))
                return false;
 
            Users user = repository.GetUser(username);
            string hash = FormsAuthentication.HashPasswordForStoringInConfigFile(newPassword.Trim(), "md5");
 
            user.Password = hash;
            repository.Save();
 
            return true;
        }

A teraz zmienić konfiguracje w webconfig

 
<connectionStrings>
    <add name="EFDbContext" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=Dziennik;Database=Dziennik;Integrated Security=TRUE "   providerName="System.Data.SqlClient" />
  </connectionStrings>
<membership defaultProvider="DziennikMembershipProvider">
      <providers>
        <clear />
        <add name="DziennikMembershipProvider" type="Dziennik_MVC.Helpers.DziennikMembershipProvider" connectionStringName="EFDbContext" />
      </providers>
    </membership>
    <profile>
      <providers>
        <clear />
      </providers>
    </profile>
    <roleManager defaultProvider="DziennikRoleProvider" enabled="true" cacheRolesInCookie="true">
      <providers>
        <clear />
        <add name="DziennikRoleProvider" type="Dziennik_MVC.Helpers.DziennikRoleProvider" connectionStringName="EFDbContext" />
      </providers>
    </roleManager>
0

Najlepiej znaleźć gotowe providery i tylko je dostosować do swojej bazy. Ja tak zrobiłem przy połączeniu się z bazą przez NHibernate'a.

0

Zamiast providerów możesz napisać własne IIdentity oraz IPrincipal (zapytaj google). Użytkownika logujesz FormsAuthentication.SetAuthCookie, rolę sprawdzasz IPrincipal.IsInRole.
IMO lepsza metoda, jeśli nie potrzebujesz sterty bzdetów z providerów(które trzeba samemu zaimplementować).

0

Chyba jednak będę potrzebował tej "sterty bzdetów". Dziękuje wszystkim za cenne wskazówki.

0

Pisze post pod postem żeby odświeżyć...
Mam jeszcze kilka pytań :P MembershipProvider jest wymagany tylko do współpracy z Website Administration tool? Czy metody z tej klasy są jeszcze gdzieś indziej wywoływane "po kryjomu"? Chciałbym np. zrobić rejestrację z większą ilością pól np. na adres, ale i tak nie zwiększę ilości argumentów w metodzie dziedziczącej po abstrakcyjnej, dlatego napisał bym dodatkową ze swoim "widzi mi się" i nie korzystał praktycznie w ogóle z tych zaimplementowanych w MembershipProvider.
Następne pytanie czy jest możliwość zmieniania szablonów na podstawie, których są generowane automatyczne metody create, details, edit, delete? Jeśli tak to gdzie to siedzi bo jakoś w gąszczu plików w projekcie tego się nie doszukałem a zmiana z osobna każdego automatycznie wygenerowanego html'a jest nieco uciążliwa.

1

MembershipProvider i RoleProvider to są mechanizmy .NET, i tak są wywoływane, dzieki nim i podobnym możesz sprawdzić czy np dany użytkownik jest zalogowany. Są pewne problemy z tymi klasami gdy chcesz je zbidnować np. Ninjectem(podobno w nowej wersji temat został zauktualizowany).

Rejestrację możesz zrobić w ten sposób że nie implementujesz metody z interfejsu tylko ją przeciążasz, np. :

public void CreateUser(string username, string fullName, string password, string email, string adres)
{
    this.repository.CreateUser(username, fullName, password, email, adres);
}

Co do generowanego kodu, musisz zmienić szablony T4. Poczytaj.

http://blogs.msdn.com/b/joecar/archive/2011/01/06/add-the-asp-net-mvc-3-code-templates-to-your-application-with-nuget.aspx

1 użytkowników online, w tym zalogowanych: 0, gości: 1