2014-09-08 11 views
5

Ho un'app MVC5 che utilizza l'autenticazione individuale e, naturalmente, l'identità ASP.NET. Il punto è che avevo esteso Ho un modello che eredita da ApplicationUser, esso è semplicemente definito in questo modo:Come posso ottenere i campi specifici dell'utente attualmente connesso in MVC5?

public class NormalUser : ApplicationUser 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
} 

Quindi, il punto è che, prima di tutto voglio verificare se c'è un logged- in utente, e se c'è, voglio ottenere i suoi campi FirstName, LastName ed Email. Come posso ottenerlo?

Penso di aver bisogno di usare qualcosa come questo per verificare se v'è un utente connesso:

if (Request.IsAuthenticated) 
{ 
    ... 
} 

Ma, come posso ottenere valori di quei campi specifici per l'utente corrente?

+0

si fa a non utilizzare o implementare un codice che utilizza 'PrincipalContext' – MethodMan

+0

@DJKRAZE Nessuna idea su di esso. – tett

+0

è molto semplice da usare e si possono ottenere presso il nome di utenti tramite athe samAccount ci sono molti esempi in realtà .. quando l'utente avvia la pagina o un sito si può facilmente ottenere in quel informazioni – MethodMan

risposta

2

Sì, in Identità, se sono necessarie ulteriori informazioni utente, è sufficiente estrarre l'utente dal database, poiché questo è ora memorizzato sull'oggetto utente corrente.

if (Request.IsAuthenticated) 
{ 
    var user = UserManager.FindById(User.Identity.GetUserId()); 
} 

Se GetUserId non è in User.Identity, aggiungere il seguente al tuo usings:

using Microsoft.AspNet.Identity; 
+0

Per estrarre i dati dal DB ogni volta che è necessario il nome e il cognome dell'utente mi sembra molto inefficiente. –

+0

Funziona perfettamente per ottenere l'e-mail, ma non per ottenere i campi FirstName e LastName. Usando quanto sopra posso solo ottenere i campi standard ApplicationUser, non i campi che ho aggiunto in seguito. – tett

+1

Oh, stai parlando della sottoclasse. Bene, quando istanziate 'UserManager', dovete specificare la classe utente che verrà utilizzata. Probabilmente stai usando il default che è "UserManager ", che restituirà solo istanze di 'ApplicationUser' che non hanno proprietà' FirstName' e 'LastName'. Quindi, puoi istanziare 'UserManager ' o semplicemente usare il tuo contesto direttamente tramite 'context.Users.OfType .Fin (User.Identity.GetUserId())' –

7

Nel MVC5 i dati utente vengono memorizzati per impostazione predefinita nella sessione e su richiesta i dati viene analizzato in un ClaimsPrincipal che contiene il nome utente (o id) e le attestazioni.

Questo è il modo in cui ho scelto di implementarlo, potrebbe non essere la soluzione più semplice ma sicuramente lo rende facile da usare.

Esempio di utilizzo:

In controllore:

public ActionResult Index() 
{ 
    ViewBag.ReverseDisplayName = this.User.LastName + ", " + this.User.FirstName; 
} 

Tenuto o _Layout:

@if(User.IsAuthenticated) 
{ 
    <span>@User.DisplayName</span> 
} 

1. Sostituire ClaimsIdentityFactory

using System.Security.Claims; 
using System.Threading.Tasks; 
using Domain.Models; 
using Microsoft.AspNet.Identity; 

public class AppClaimsIdentityFactory : IClaimsIdentityFactory<User, int> 
{ 
    internal const string IdentityProviderClaimType = "http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider"; 

    internal const string DefaultIdentityProviderClaimValue = "My Identity Provider"; 

    /// <summary> 
    ///  Constructor 
    /// </summary> 
    public AppClaimsIdentityFactory() 
    { 
     RoleClaimType = ClaimsIdentity.DefaultRoleClaimType; 
     UserIdClaimType = ClaimTypes.NameIdentifier; 
     UserNameClaimType = ClaimsIdentity.DefaultNameClaimType; 
     SecurityStampClaimType = Constants.DefaultSecurityStampClaimType; 
    } 

    /// <summary> 
    ///  Claim type used for role claims 
    /// </summary> 
    public string RoleClaimType { get; set; } 

    /// <summary> 
    ///  Claim type used for the user name 
    /// </summary> 
    public string UserNameClaimType { get; set; } 

    /// <summary> 
    ///  Claim type used for the user id 
    /// </summary> 
    public string UserIdClaimType { get; set; } 

    /// <summary> 
    ///  Claim type used for the user security stamp 
    /// </summary> 
    public string SecurityStampClaimType { get; set; } 

    /// <summary> 
    ///  Create a ClaimsIdentity from a user 
    /// </summary> 
    /// <param name="manager"></param> 
    /// <param name="user"></param> 
    /// <param name="authenticationType"></param> 
    /// <returns></returns> 
    public virtual async Task<ClaimsIdentity> CreateAsync(UserManager<User, int> manager, User user, string authenticationType) 
    { 
     if (manager == null) 
     { 
      throw new ArgumentNullException("manager"); 
     } 
     if (user == null) 
     { 
      throw new ArgumentNullException("user"); 
     } 
     var id = new ClaimsIdentity(authenticationType, UserNameClaimType, RoleClaimType); 
     id.AddClaim(new Claim(UserIdClaimType, user.Id.ToString(), ClaimValueTypes.String)); 
     id.AddClaim(new Claim(UserNameClaimType, user.UserName, ClaimValueTypes.String)); 
     id.AddClaim(new Claim(IdentityProviderClaimType, DefaultIdentityProviderClaimValue, ClaimValueTypes.String)); 

     id.AddClaim(new Claim(ClaimTypes.Email, user.EmailAddress)); 
     if (user.ContactInfo.FirstName != null && user.ContactInfo.LastName != null) 
     { 
      id.AddClaim(new Claim(ClaimTypes.GivenName, user.ContactInfo.FirstName)); 
      id.AddClaim(new Claim(ClaimTypes.Surname, user.ContactInfo.LastName)); 
     } 

     if (manager.SupportsUserSecurityStamp) 
     { 
      id.AddClaim(new Claim(SecurityStampClaimType, 
       await manager.GetSecurityStampAsync(user.Id))); 
     } 
     if (manager.SupportsUserRole) 
     { 
      user.Roles.ToList().ForEach(r => 
       id.AddClaim(new Claim(ClaimTypes.Role, r.Id.ToString(), ClaimValueTypes.String))); 
     } 
     if (manager.SupportsUserClaim) 
     { 
      id.AddClaims(await manager.GetClaimsAsync(user.Id)); 
     } 
     return id; 
    } 

2. Modificare la UserManager usarlo

public static UserManager<User,int> Create(IdentityFactoryOptions<AppUserManager> options, IOwinContext context) 
{ 
    var manager = new UserManager<User,int>(new UserStore<User,int>(new ApplicationDbContext())) 
    { 
     ClaimsIdentityFactory = new AppClaimsIdentityFactory() 
    }; 

    // more initialization here 

    return manager; 
} 

3. Creare un nuovo personalizzato Principal

using System; 
using System.Collections.Generic; 
using System.Globalization; 
using System.Linq; 
using System.Security.Claims; 

public class UserPrincipal : ClaimsPrincipal 
{ 
    public UserPrincipal(ClaimsPrincipal principal) 
     : base(principal.Identities) 
    { 
    } 

    public int UserId 
    { 
     get { return FindFirstValue<int>(ClaimTypes.NameIdentifier); } 
    } 

    public string UserName 
    { 
     get { return FindFirstValue<string>(ClaimsIdentity.DefaultNameClaimType); } 
    } 

    public string Email 
    { 
     get { return FindFirstValue<string>(ClaimTypes.Email); } 
    } 

    public string FirstName 
    { 
     get { return FindFirstValue<string>(ClaimTypes.GivenName); } 
    } 

    public string LastName 
    { 
     get { return FindFirstValue<string>(ClaimTypes.Surname); } 
    } 

    public string DisplayName 
    { 
     get 
     { 
      var name = string.Format("{0} {1}", this.FirstName, this.LastName).Trim(); 
      return name.Length > 0 ? name : this.UserName; 
     } 
    } 

    public IEnumerable<int> Roles 
    { 
     get { return FindValues<int>(ClaimTypes.Role); } 
    } 

    private T FindFirstValue<T>(string type) 
    { 
     return Claims 
      .Where(p => p.Type == type) 
      .Select(p => (T)Convert.ChangeType(p.Value, typeof(T), CultureInfo.InvariantCulture)) 
      .FirstOrDefault(); 
    } 

    private IEnumerable<T> FindValues<T>(string type) 
    { 
     return Claims 
      .Where(p => p.Type == type) 
      .Select(p => (T)Convert.ChangeType(p.Value, typeof(T), CultureInfo.InvariantCulture)) 
      .ToList(); 
    } 
} 

4. Creare un AuthenticationFilter usarlo

using System.Security.Claims; 
using System.Web.Mvc; 
using System.Web.Mvc.Filters; 


public class AppAuthenticationFilterAttribute : ActionFilterAttribute, IAuthenticationFilter 
{ 
    public void OnAuthentication(AuthenticationContext filterContext) 
    { 
     //This method is responsible for setting and modifying the principle for the current request though the filterContext . 
     //Here you can modify the principle or applying some authentication logic. 
     var principal = filterContext.Principal as ClaimsPrincipal; 
     if (principal != null && !(principal is UserPrincipal)) 
     { 
      filterContext.Principal = new UserPrincipal(principal); 
     } 
    } 

    public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext) 
    { 
     //This method is responsible for validating the current principal and permitting the execution of the current action/request. 
     //Here you should validate if the current principle is valid/permitted to invoke the current action. (However I would place this logic to an authorization filter) 
     //filterContext.Result = new RedirectToRouteResult("CustomErrorPage",null); 
    } 
} 

5.Registrare il filtro di autenticazione per caricare a livello globale nel FilterConfig

public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
{ 
    filters.Add(new HandleErrorAttribute()); 
    filters.Add(new AppAuthenticationFilterAttribute()); 
} 

Ormai il Principal viene mantenuto e tutti noi abbiamo lasciato fare è esporla nel controller e Vista.

6. Creare una classe base controller

public abstract class ControllerBase : Controller 
{ 
    public new UserPrincipal User 
    { 
     get { return HttpContext.User as UserPrincipal; } 
    } 
} 

7. Creare una classe base WebViewPage e modificare il web.config di usarlo

public abstract class BaseViewPage : WebViewPage 
{ 
    public virtual new UserPrincipal User 
    { 
     get { return base.User as UserPrincipal; } 
    } 

    public bool IsAuthenticated 
    { 
     get { return base.User.Identity.IsAuthenticated; } 
    } 
} 

public abstract class BaseViewPage<TModel> : WebViewPage<TModel> 
{ 
    public virtual new UserPrincipal User 
    { 
     get { return base.User as UserPrincipal; } 
    } 

    public bool IsAuthenticated 
    { 
     get { return base.User.Identity.IsAuthenticated; } 
    } 
} 

E la web.config all'interno della cartella Views :

<pages pageBaseType="MyApp.Web.Views.BaseViewPage"> 

Importante!

Non memorizzare troppi dati su Principal poiché questi dati vengono passati avanti e indietro su ogni richiesta.

+1

(non è colpa tua) Questo è matto cosa stava pensando la SM? Bontà. – toddmo

Problemi correlati