11

Ich bin ein Intranet Anwendung mit MVC3 mit einem MSSQL-Backend bauen. Ich habe Authentifizierung und Rollen (über einen benutzerdefinierten Rollenanbieter) ordnungsgemäß funktioniert. Ich versuche jetzt, User.Identity zu überschreiben, um Elemente wie User.Identity.FirstName zuzulassen. Aber ich kann keinen Code finden, die mir zeigen, wie dies in WindowsMVC3 Windows-Authentifizierung überschreiben User.Identity

Ich habe versucht, einen benutzerdefinierten Anbieter zu schreiben:

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; } 
} 

und Überschreiben die WindowsAuthentication das benutzerdefinierte Haupt zu füllen.

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

Ich habe einen Haltepunkt in der Authentifizierungsfunktion und der Prinzipal wird bevölkert; Wenn ich jedoch einen Haltepunkt in die Controller setze, ist der Benutzer nur das normale RolePrincipal, anstelle meines benutzerdefinierten Principals. Was mache ich falsch?

EDIT:

bemerkte ich aus dem Code oben in der global.asax. Ich habe die AuthorizeAttribute mit C# außer Kraft gesetzt:

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; 
    } 

} 

Und mein Auftraggeber die angepasst folgende:

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(); 
    } 
} 

Jetzt habe ich, wenn ich in einen Haltepunkt setzen, zeigt die Uhr in Benutzer die folgenden:

  • Benutzer
    • [CSupport.Model.CPrincipal]
    • Identität

Identität ist zugänglich; es ist jedoch immer noch die WindowsIdentity CPrincipal ist nur in der Uhr zugänglich und nicht direkt zugänglich.

EDIT: Danke an alle, die dazu beigetragen haben. Sie haben mein Verständnis der Funktionsweise der verschiedenen Teile erheblich erweitert.

Ich hatte beide Möglichkeiten zu arbeiten, also dachte ich, ich würde teilen.

Option 1: Überschreiben Sie die Autorisieren Anfrage in Global.asax

Das ist das, was ich mit gehe.

Ich habe Application_AuthenticateRequest nicht verwendet, weil (entsprechend: HttpContext.Current.User is null even though Windows Authentication is on) der Benutzer nicht in einem Windows-Authentifizierungsprozess ausgefüllt wurde und daher gibt es nichts, das ich verwenden kann, um die Benutzerinformationen abzurufen.

Application_AuthorizeRequest ist der nächste in der Kette und passiert, nachdem die Windows-Identität eingegeben wurde.

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

Dies ist die Überschreibung der Haupt

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); 
    } 
} 

Dies ist, wie Sie die aktualisierte Informationen in dem neuen Haupt zuzugreifen, die erstellt wurde.

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

Option 2: Überschreiben Sie die AuthorizeAttribute

Dies ist die überschriebene Auftraggeber ist (Es ist das gleiche wie oben)

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); 
    } 
} 

Hier ist die Überschreibung der Autorisieren

Attribut
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; 
    } 

} 

Hier können Sie das AuthorizeAttribute ändern, um die neuen Informa zu verwenden und zu verwenden tion.

Option 1 behandelt alles global, Option 2 behandelt alles auf einer individuellen Ebene.

+0

Warten ... Was ist das Ereignishandler? Sie versuchen nicht, das ASP.NET-Login-Steuerelement zu verwenden? Wo befindet sich dieses Ereignis und an welches Ereignis knüpft es an? –

+0

Ich verwende Windows-Authentifizierung auf einer Intranetsite. Dieser Event-Handler befindet sich im globalen Bereich.asax –

+0

In global.asax gibt es keinen OnAuthenticate-Handler. Wahrscheinlich hast du deswegen Probleme. –

Antwort

6

Anstatt dies auf diese Weise zu tun, sollten Sie die Application_AuthenticateRequest-Methode in global.asax überschreiben und dann Current.User anstelle von HttpContext.Current.User verwenden (nicht sicher, warum, aber es gibt einen Unterschied).

Dann ist eine einfache Möglichkeit, auf diese in Ihrem Controller zuzugreifen, eine Erweiterungsmethode zu erstellen? Etwas wie dieses:

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

dann können Sie einfach User.Identity.IMyIdenty().FirstName sagen. Sie könnten dies wahrscheinlich auch als Eigentum tun. Hier

ist der Code, den ich verwenden:

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()); 
} 

Nun, ignorieren die DependencyResolver Sachen und die benutzerdefinierte Auth Ticket Zeug, das ist ziemlich einfach und funktioniert bei mir richtig.

Dann, in meiner App, wenn ich Informationen aus meiner benutzerdefinierten Identität brauche, ich es einfach mit ((IMyIdentity)User.Identity).FirstName oder was auch immer ich brauche. Es ist keine Raketenwissenschaft, und es funktioniert.

+0

Ich habe nur den authenticaterequest Teil versucht und bekam: HttpContext.Current.User ist null und Current existiert nicht. 'Protected void Application_AuthenticateRequest (object sender, EventArgs e) { if (HttpContext.Current.User.Identity! = Null && HttpContext.Current.User.Identity.IsAuthenticated) { HttpContext.Current.User = new CPrincipal (Httpcontext .Current.User.Identity); } } ' –

+0

@TobyJones - siehe meine Bearbeitung. Es ist Ihre Aufgabe, die Authentifizierung in AuthenticateRequest durchzuführen. Der Benutzer ist natürlich Null, weil noch keine Authentifizierung stattgefunden hat. –

2

What am I doing wrong?

Wahrscheinlich überschreibt das Attribut [Authorize] Ihre Änderungen. Anstatt also, dies zu tun in der WindowsAuthentication_OnAuthenticate Methode in Ihrem Global.asax schreibt ein benutzerdefiniertes Authorize Attribut, etwa so:

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; 
    } 
} 

und verwenden Sie dann Ihre benutzerdefiniertes Attribut anstelle des Standard ein:

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

In ASP. NET MVC Die Standardmethode zum Ausführen der Autorisierung besteht in Autorisierungsaktionsfiltern und nicht in Ereignissen in Global.asax.

+0

Das Autorisierungsattribut überschreibt Ihren Kontext nicht. –

+1

Wie auch immer, es ist eine schlechte Übung, Ereignisse in 'Global.asax' zu verwenden, um die Autorisierung in einer ASP.NET MVC-Anwendung durchzuführen. Sie sollten stattdessen benutzerdefinierte Autorisierungsfilter verwenden. –

+1

Er macht keine Autorisierung in seinem Code, er wendet nur seinen benutzerdefinierten Principal an, den afaik in global.asax noch tun sollte. –