2016-09-12 104 views
5

Chcę użyć ASP.NET MVC 5 dla mojej aplikacji internetowej. Potrzebuję użyć windows authentication.Gdzie mogę załadować informacje o użytkowniku do sesji w ASP.NET MVC 5 z uwierzytelnianiem Windows?

Jeśli korzystam z windows authentication, gdzie jest najlepsze miejsce do odczytywania informacji użytkownika (userid i ról) i zapisania go do Session?

mam metodę uzyskiwania informacji użytkownika przez nazwę użytkownika z bazy danych tak:

public class CurrentUser 
    { 
     public int UserId { get; set; } 

     public string UserName { get; set; } 

     public Roles Roles { get; set; } 
    } 

    public enum Roles 
    { 
     Administrator, 
     Editor, 
     Reader 
    } 

    public class AuthService 
    { 
     public CurrentUser GetUserInfo(string userName) 
     { 
      var currentUser = new CurrentUser(); 

      //load from DB 

      return currentUser; 
     } 
    } 

Odpowiedz

2

Zadałeś dwa pytania (1) najlepsze miejsce do uzyskania informacji o użytkowniku i (2) jak je zapisać w sesji. Odpowiem (1) iw ten sposób być może pokażę, że nie musisz umieszczać żadnych dodatkowych informacji w sesji.

Poinformowałeś, że twoja aplikacja używa uwierzytelniania systemu Windows, więc oznacza to, że ciężka praca nad uwierzytelnieniem użytkownika została już wykonana przez IIS/HttpListener zanim aplikacja otrzyma żądanie. Po otrzymaniu żądania pojawi się WindowsPrincipal w HttpContext.User. Będzie to miało już nazwę użytkownika Windows i role AD już ustalone, ale chcesz użyć dodatkowych ról przechowywanych w bazie danych ...

Możesz uzyskać dostęp do swojej AuthService z dowolnego miejsca w aplikacji, ale prawdopodobnie najlepszym sposobem jest zarejestrowanie IAuthorizationFilter i wykonaj tam pracę. Postępując zgodnie z tym podejściem, dodatkowe role i inne informacje pobierane z bazy danych będą dostępne w metodach kontrolera i, co być może ważniejsze, z dodatkowego kodu biblioteki, który wymaga sprawdzenia poświadczeń użytkownika.

Przed .Net 4.5, jeśli chcesz dodać dodatkowe informacje do WindowsPrincipal Myślę, że Twoim jedynym wyborem było zastąpienie dostarczonego przez system użytkownika innym obiektem, który zaimplementował interfejs IPrincipal. To podejście jest nadal dostępne (i co polecam), ale od czasu wprowadzenia Windows Identity Foundation (WIF) w .Net 4.5, WindowsPrincipal pochodzi z  System.Security.Claims.ClaimsIdentityClaimsIdentity, który obsługuje dodawanie dodatkowych ról (i innych użytecznych informacji) do głównego systemu podanego przez użytkownika. Jednak, jak zauważyło kilka osób, w systemie Windows występuje błąd/funkcja, która może powodować zgłaszanie wyjątku podczas sprawdzania ról, które zostały dodane programowo. Stwierdziliśmy, że prostym i niezawodnym sposobem uniknięcia tego jest zastąpienie Użytkownika numerem GenericPrincipal.

wymaganych etapów:

(1) tworzą się IAuthorizationFilter.

class MyAuthorizationFilter : IAuthorizationFilter 
{ 
    AuthService _authService; 

    public MyAuthorizationFilter(AuthService authService) 
    { 
     _authService = authService; 
    } 

    public void OnAuthorization(AuthorizationContext filterContext) 
    { 
     var principal = filterContext.HttpContext.User; 

     if (principal.Identity != null && principal.Identity.IsAuthenticated) 
     { 
      // Add username (and other details) to session if you have a need 
      filterContext.HttpContext.Session["User"] = principal.Identity.Name; 

      // get user info from DB and embue the identity with additional attributes 
      var user = _authService.GetUserInfo(principal.Identity.Name); 

      // Create a new Principal and add the roles belonging to the user 
      GenericPrincipal gp = new GenericPrincipal(principal.Identity, user.RoleNames.ToArray()); 
      filterContext.HttpContext.User = gp; 
     } 
    } 
} 

(2) Zarejestruj swój filtr. Można to zarejestrować na poziomie kontrolera lub globalnie. Zazwyczaj można to zrobić w App_Start\FilterConfig.cs:

public class FilterConfig 
{ 
    public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
    { 
     filters.Add(new MyAuthorizationFilter(new AuthService())); 
    } 
} 

(3) Za pomocą dostarczonego GenericPrincipal w kodzie aplikacji, aby odpowiedzieć na pytania dotyczące identyfikacji użytkownika i innych danych uwierzytelniających. na przykład w swojej metodzie sterownika możesz uzyskać dostęp do nazwy użytkownika lub innych "roszczeń" (np. adresu e-mail) zapisanych w filtrze GenericPrincipal przez filtr.

 public ActionResult Index() 
     { 
      ViewBag.Name = HttpContext.User.Identity.Name; 
      if(HttpContext.User.IsInRole("Administrator")) 
      { 
       // some role-specific action 
      } 
      return View(); 
     } 

Ponieważ używałem wbudowanego mechanizmu nagrać Principal role, można uzyskać dostęp z dowolnego dane użytkownika za pomocą HttpContext.User lub System.Threading.Thread.CurrentPrincipal. Możesz także użyć metody kontrolera, aby zadeklarować, które akcje są dostępne dla określonych ról lub użytkowników. na przykład

public class HomeController : Controller 
    { 
     [Authorize(Roles = "Administrator")] 
     public ActionResult Admin() 
     { 
      return View(); 
     } 

Zobacz MSDN celu uzyskania dalszych informacji na temat ClaimsIdentity

Mam nadzieję, że to pomoże

-Rob

+0

Rob Bardzo dziękuję za odpowiedź. Twoje rozwiązanie polegające na uzyskiwaniu ról jest niesamowite, ale bardzo potrzebuję uzyskać userid do sesji z powodów takich, jak pobranie pewnych informacji z bazy danych według userid itp. Czy mogę pomóc mi uzyskać userid do sesji? :-) Nie wiem, gdzie jest najlepsze miejsce do zrobienia? Dzięki. – Jenan

+0

Cześć Jenan. Możesz dodać nazwę użytkownika do sesji w polu AuthorizationFilter, jeśli musisz (zaktualizowałem odpowiedź, aby to pokazać), ale nie jestem pewien, dlaczego musiałbyś to zrobić. Możesz uzyskać dostęp do Zleceniodawcy (i od niego Identity.Username) z dowolnego kodu za pomocą HttpConext.User (w swoim kontrolerze) lub, jeśli jesteś głębiej w bibliotece kodu, możesz użyć System.Threading.Thread.CurrentPrincipal. – Rob

+0

Rob, dziękuję bardzo za poświęcony czas. Ta odpowiedź jest dla mnie wspaniała. – Jenan

1

przede wszystkim; nigdy nigdy, nigdy szczegóły sklep użytkowników w sesji. Poważnie. Po prostu tego nie rób.

Jeśli używasz Windows Auth, użytkownik jest w AD. Masz AD, aby uzyskać informacje o użytkowniku. Firma Microsoft ma numer MSDN article opisujący, w jaki sposób należy to zrobić.

Długie i krótkie jest to, że należy utworzyć podklasę UserIdentity i przedłużyć go o dodatkowe właściwości, które chcą powrócić na użytkownika:

[DirectoryRdnPrefix("CN")] 
[DirectoryObjectClass("inetOrgPerson")] 
public class InetOrgPerson : UserPrincipal 
{ 
    // Inplement the constructor using the base class constructor. 
    public InetOrgPerson(PrincipalContext context) : base(context) 
    { 
    } 

    // Implement the constructor with initialization parameters.  
    public InetOrgPerson(PrincipalContext context, 
         string samAccountName, 
         string password, 
         bool enabled) 
         : base(context, 
           samAccountName, 
           password, 
           enabled) 
    { 
    } 

    InetOrgPersonSearchFilter searchFilter; 

    new public InetOrgPersonSearchFilter AdvancedSearchFilter 
    { 
     get 
     { 
      if (null == searchFilter) 
       searchFilter = new InetOrgPersonSearchFilter(this); 

      return searchFilter; 
     } 
    } 

    // Create the mobile phone property.  
    [DirectoryProperty("mobile")] 
    public string MobilePhone 
    { 
     get 
     { 
      if (ExtensionGet("mobile").Length != 1) 
       return null; 

      return (string)ExtensionGet("mobile")[0]; 
     } 

     set 
     { 
      ExtensionSet("mobile", value); 
     } 
    } 

    ... 
} 

W kodzie powyższym przykładzie właściwość jest dodawany do wiązania do pola użytkownika użytkownika AD w polu mobile. Odbywa się to poprzez zaimplementowanie właściwości, jak pokazano przy użyciu ExtensionSet, a następnie adnotację właściwości za pomocą atrybutu DirectoryProperty, aby określić, z którym polem wiąże.

Atrybuty klasy DirectoryRdnPrefix i DirectoryObjectClass muszą być zgodne z konfiguracją AD.

Po zaimplementowaniu tego będzie można uzyskać wartości po prostu odwołując je User.Identity. Na przykład: User.Identity.MobilePhone zwróci pole mobile z AD dla użytkownika.

+0

Dziękuję za odpowiedź. Dlaczego nie przechowywać informacji o użytkowniku w sesji? – Jenan

+0

Po pierwsze, sesja w ogóle powinna być używana oszczędnie, jeśli w ogóle. Sesje są zło konieczne, a nie coś, co powinieneś używać często lub na kaprys. Po drugie, sesje są z natury niepewne. Istnieją sposoby, aby uczynić je bardziej "bezpiecznymi" przy użyciu HTTPS i flag takich jak 'HTTPOnly' i' Secure' podczas ustawiania plików cookie, ale nadal ujawniają luki w zabezpieczeniach, które nie istniałyby inaczej. Ponieważ musimy polegać na nich przynajmniej w takich kwestiach jak uwierzytelnianie, najlepszym sposobem na złagodzenie ekspozycji. Odbywa się to przez uwzględnienie jedynie konieczności uzyskiwania informacji w celu odzyskania użytkownika. –

+0

Coś jak identyfikator użytkownika, na przykład, nie ma żadnego znaczenia bez dostępu do bazy danych, w której znajduje się identyfikator użytkownika, więc uwzględnienie jej w pliku cookie sesji jest względnie nieszkodliwe, ale gdy zaczynasz dodawać takie rzeczy jak imię i nazwisko, adres, e-mail, telefon, itp. w sesji, wtedy masz możliwość wycieku wszystkich tych danych osobowych. –

Powiązane problemy