11

Sto creando un'applicazione intranet utilizzando MVC3 con un backend MSSQL. Ho un'autenticazione e ruoli (attraverso un fornitore di ruoli personalizzati) che funzionano correttamente. Quello che sto cercando di fare ora è sovrascrivere User.Identity per consentire elementi come User.Identity.FirstName. Ma non riesco a trovare alcun codice che mi mostrerà come fare questo in WindowsIdentityMVC3 Autenticazione di Windows ignora User.Identity

Ho provato a scrivere un provider personalizzato:

public class CPrincipal : WindowsPrincipal 
{ 
    UserDAL userDAL = new UserDAL(); 
    public CPrincipal(WindowsIdentity identity) 
     : base(identity) 
    { 
     userInfo = userDAL.GetUserProfile(identity.Name.Split('\\')[1]); 
     this.identity = identity; 
    } 
    public UserInfo userInfo { get; private set; } 
    public WindowsIdentity identity { get; private set; } 
} 

e ignorando l'WindowsAuthentication per popolare il preside personalizzata.

void WindowsAuthentication_OnAuthenticate(object sender, WindowsAuthenticationEventArgs e) 
    { 
     if (e.Identity != null && e.Identity.IsAuthenticated) 
     { 
      CPrincipal cPrincipal = new CPrincipal(e.Identity); 
      HttpContext.Current.User = cPrincipal; 
     } 
    } 

Ho un punto di interruzione nella funzione di autenticazione e il principale viene popolato; tuttavia, quando inserisco un punto di interruzione nei controller, l'utente è solo il suo normale RolePrincipal, anziché il mio principal personalizzato. Che cosa sto facendo di sbagliato?

EDIT:

ho commentato il codice sopra nella global.asax. ho ignorato l'AuthorizeAttribute utilizzando C#:

public class CAuthorize : AuthorizeAttribute 
{ 
    protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
     bool authorized = base.AuthorizeCore(httpContext); 
     if (!authorized) 
     { 
      return false; 
     } 


     IIdentity user = httpContext.User.Identity; 
     CPrincipal cPrincipal = new CPrincipal(user); 
     httpContext.User = cPrincipal; 

     return true; 
    } 

} 

e regolato il mio principale al seguente:

public class CPrincipal : IPrincipal 
{ 
    private UserDAL userDAL = new UserDAL(); 
    public CPrincipal(IIdentity identity) 
    { 
     userInfo = userDAL.GetUserProfile(identity.Name.Split('\\')[1]); 
     this.Identity = identity; 
    } 
    public UserInfo userInfo { get; private set; } 

    public IIdentity Identity { get; private set; } 

    public bool IsInRole(string role) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Ora io quando ho messo un punto di interruzione, l'orologio mostra quanto segue utente:

  • utente
    • [CSupport.Model.CPrincipal]
    • Identità

identità è accessibile; tuttavia, è ancora WindowsIdentity CPrincipal è accessibile solo nell'orologio e non è accessibile direttamente.

MODIFICA: Grazie a tutti coloro che hanno contribuito a questo. Hai notevolmente ampliato la mia comprensione di come funzionano le varie parti.

Ho avuto entrambi i modi di lavorare, quindi ho pensato di condividere.

Opzione 1: Eseguire l'override del Request Autorizza in Global.asax

Questo è quello che sto con.

Non ho utilizzato Application_AuthenticateRequest perché (in base a questo: HttpContext.Current.User is null even though Windows Authentication is on) l'utente non è stato popolato in un processo di autenticazione di Windows e quindi non c'è nulla che possa essere utilizzato per ottenere le informazioni dell'utente.

Application_AuthorizeRequest è il prossimo della catena e si verifica dopo l'introduzione dell'identità di Windows.

protected void Application_AuthorizeRequest(object sender, EventArgs e) 
    { 
     if (User.Identity.IsAuthenticated && Roles.Enabled) 
     { 
      Context.User = new FBPrincipal(HttpContext.Current.User.Identity); 
     } 
    } 

Questa è l'override del Principal

public class CPrincipal : IPrincipal 
{ 
    private UserDAL userDAL = new UserDAL(); 
    public CPrincipal(IIdentity identity) 
    { 
     userInfo = userDAL.GetUserProfile(identity.Name.Split('\\')[1]); 
     this.Identity = identity; 
    } 
    public UserInfo userInfo { get; private set; } 

    public IIdentity Identity { get; private set; } 

    public bool IsInRole(string role) 
    { 
     return userDAL.IsUserInRole(userInfo.UserName, role); 
    } 
} 

In questo modo si accede alla informazioni aggiornate nel nuovo Principal che è stato creato.

[Authorize(Roles = "super admin")] 
    public ActionResult Dashboard() 
    { 
     string firstname = (User as CPrincipal).userInfo.FirstName; // <-- 
     DashboardModel dModel = reportDAL.GetChartData(); 
     return View(dModel); 
    } 

Opzione 2: Eseguire l'override del AuthorizeAttribute

Questa è la principale sovrascritto (E 'lo stesso come sopra)

public class CPrincipal : IPrincipal 
{ 
    private UserDAL userDAL = new UserDAL(); 
    public CPrincipal(IIdentity identity) 
    { 
     userInfo = userDAL.GetUserProfile(identity.Name.Split('\\')[1]); 
     this.Identity = identity; 
    } 
    public UserInfo userInfo { get; private set; } 

    public IIdentity Identity { get; private set; } 

    public bool IsInRole(string role) 
    { 
     return userDAL.IsUserInRole(userInfo.UserName, role); 
    } 
} 

Ecco l'override del Autorizza Attributo

public class CAuthorize : AuthorizeAttribute 
{ 
    protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
     bool authorized = base.AuthorizeCore(httpContext); 
     if (!authorized) 
     { 
      return false; 
     } 


     IIdentity user = httpContext.User.Identity; 
     CPrincipal cPrincipal = new CPrincipal(user); 
     httpContext.User = cPrincipal; 

     return true; 
    } 

} 

Qui è dove si modifica quale AuthorizeAttribute utilizzare e si utilizzano le nuove informazioni zione.

[CAuthorize(Roles = "super admin")] // <-- 
    public ActionResult Dashboard() 
    { 
     string firstname = (User as CPrincipal).userInfo.FirstName; // <-- 
     DashboardModel dModel = reportDAL.GetChartData(); 
     return View(dModel); 
    } 

L'opzione 1 gestisce tutto a livello globale, l'opzione 2 gestisce tutto a livello individuale.

+0

Attendi ... Che cos'è questo gestore eventi? Non stai provando a usare il controllo di accesso di ASP.NET sei? Dove si trova questo evento e in quale evento si sta vincolando? –

+0

Sto usando l'autenticazione di Windows su un sito intranet. Questo gestore di eventi è globale.asax –

+0

Non esiste un gestore OnAuthenticate in global.asax. Questo è probabilmente il motivo per cui hai problemi. –

risposta

6

Invece di fare in questo modo, si dovrebbe eseguire l'override del metodo Application_AuthenticateRequest in global.asax, quindi utilizzare Current.User piuttosto che HttpContext.Current.User (non so perché, ma c'è una differenza).

Quindi, un modo semplice per accedere a questo nel controller è creare un metodo di estensione? Qualcosa di simile a questo:

public static class IIdentityExtensions { 
    public static IMyIdentity MyIdentity(this IIdentity identity) { 
     return (IMyIdentity)identity; 
    } 
} 

allora si può solo dire User.Identity.IMyIdenty().FirstName. Probabilmente potresti farlo anche come proprietà.

ecco il codice che uso:

protected void Application_AuthenticateRequest(Object sender, EventArgs e) 
{ 
    FormsAuthenticationTicket authTicket = FormsAuthentication 
     .Decrypt(authCookie.Value); 
    var identity = new MyIdentity(authTicket.Name, "Forms", 
     FormsAuthenticationHelper.RetrieveAuthUserData(authTicket.UserData)); 
    Context.User = new GenericPrincipal(identity, 
     DependencyResolver.Current.GetService<ISecurityHandler>() 
      .GetRoles(identity.Name).ToArray()); 
} 

Ora, ignorando la roba DependencyResolver e la roba biglietto auth personalizzato, questo è piuttosto semplice e funziona correttamente per me.

Quindi, nella mia app, quando ho bisogno di informazioni dalla mia identità personalizzata, l'ho appena lanciato con ((IMyIdentity)User.Identity).FirstName o qualsiasi altra cosa di cui ho bisogno. Non è scienza missilistica, e funziona.

+0

Ho provato solo la parte authenticaterequest e ho ottenuto: HttpContext.Current.User è null e Current non esiste. 'Protected void Application_AuthenticateRequest (object sender, EventArgs e) { se (HttpContext.Current.User.Identity! = Null && HttpContext.Current.User.Identity.IsAuthenticated) { HttpContext.Current.User = new CPrincipal (HttpContext .Current.User.Identity); } } ' –

+0

@TobyJones - vedere la mia modifica. È tuo compito eseguire l'autenticazione in AuthenticateRequest. L'utente è ovviamente null perché non è ancora avvenuta l'autenticazione. –

2

What am I doing wrong?

Probabilmente l'attributo [Authorize] sovrascrive le modifiche. Così, invece di fare questo nel metodo WindowsAuthentication_OnAuthenticate nella vostra Global.asax scrivere un Authorize attributo personalizzato, in questo modo:

public class MyAuthorizeAttribute : AuthorizeAttribute 
{ 
    protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
     var authorized = base.AuthorizeCore(httpContext); 
     if (!authorized) 
     { 
      return false; 
     } 


     var user = httpContext.User as WindowsIdentity; 
     CPrincipal cPrincipal = new CPrincipal(user); 
     httpContext.User = cPrincipal; 

     return true; 
    } 
} 

e quindi utilizzare la vostra abitudine attribuire al posto di quello di default:

[MyAuthorize] 
public ActionResult SomeAction() 
{ 
    // User.Identity will be your custom principal here 
} 

in ASP. NET MVC il modo standard per eseguire l'autorizzazione è attraverso i filtri delle azioni di autorizzazione, non attraverso gli eventi in Global.asax.

+0

L'attributo Authorize non sovrascrive il contesto. –

+1

In ogni caso, è una pratica scorretta utilizzare gli eventi in 'Global.asax' per eseguire l'autorizzazione in un'applicazione ASP.NET MVC. Dovresti invece usare filtri di autorizzazione personalizzati. –

+1

Non sta facendo l'autorizzazione nel suo codice, sta solo applicando il suo principal personalizzato, che dovrebbe ancora essere fatto in global.asax. –