11

我正在构建一个内联网应用程序使用MVC3与MSSQL后端。我有身份验证和角色(通过自定义角色提供者)正常工作。我现在要做的是重写User.Identity以允许像User.Identity.FirstName这样的项目。但我无法找到任何代码,会告诉我如何的WindowsIdentityMVC3 Windows身份验证覆盖User.Identity

为此,我曾尝试编写自定义提供:

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

并重写WindowsAuthentication来填充自定义主体。

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

我在认证功能中有一个断点,并且正在填充主体;然而,当我在控制器中放置一个断点时,用户只是它的普通RolePrincipal,而不是我的自定义主体。我究竟做错了什么?

编辑:

我注释掉上面的代码在Global.asax。 我已经覆盖了AuthorizeAttribute使用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; 
    } 

} 

和调整,我主要在以下几点:

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

现在,我当我把一个断点,手表显示在用户执行以下操作:

  • 用户
    • [CSupport.Model.CPrincipal]
    • 身份

身份是accessable;但是,它仍然是WindowsIdentity CPrincipal只能在手表中访问,不能直接访问。

编辑: 感谢所有对此有贡献的人。您已经极大地扩展了我对各部分工作原理的理解。

我有两种工作方式,所以我想我会分享。

选项1:覆盖的授权请求在Global.asax中

这是一个我用下去。

我没有使用Application_AuthenticateRequest,因为(根据这个:HttpContext.Current.User is null even though Windows Authentication is on)用户没有在Windows身份验证过程中填充,因此没有任何可以用来获取用户信息的东西。

Application_AuthorizeRequest是链中的下一个,并在窗口标识被引入后发生。

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

这是主要的

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

的覆盖这是你如何访问所创建的新的主要更新的信息。

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

选项2:重写AuthorizeAttribute

这是被覆盖的主(这是与上述相同)

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

这里是授权的重写属性

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

} 

这是您更改哪个AuthorizeAttribute使用和使用新信息的地方灰。

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

选项1全局处理everthing,选项2处理个人级别的所有内容。

+0

等等...什么是事件处理程序?你不是在尝试使用ASP.NET登录控件吗?这个活动位于哪里,哪个活动与哪个活动相搭配? –

+0

我在内部网站上使用Windows身份验证。此事件处理程序位于全局中。asax –

+0

global.asax中没有OnAuthenticate处理程序。这可能是你遇到问题的原因。 –

回答

6

而不是这样做,你应该重写Global.asax中的Application_AuthenticateRequest方法,然后使用Current.User而不是HttpContext.Current.User(不知道为什么,但是有区别)。

然后,在控制器中访问这个简单的方法是创建一个扩展方法?类似这样的:

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

那么你可以只说User.Identity.IMyIdenty().FirstName。你也可以把它作为一个属性来做。

这里是我使用的代码:

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

现在,忽视了DependencyResolver东西和自定义身份验证票证的东西,这是非常基本和正常工作对我来说。

然后,在我的应用程序,当我需要的信息从我的定制身份,我只是((IMyIdentity)User.Identity).FirstName或任何我需要投它。这不是火箭科学,它的工作原理。

+0

我只尝试了authenticaterequest部分,得到:HttpContext.Current.User为null,Current不存在。 '保护无效Application_AuthenticateRequest(对象发件人,EventArgs的){ 如果 (HttpContext.Current.User.Identity!= NULL && HttpContext.Current.User.Identity.IsAuthenticated) { HttpContext.Current.User =新CPrincipal(HttpContext的.Current.User.Identity); } }' –

+0

@TobyJones - 请参阅我的编辑。在AuthenticateRequest中执行身份验证是您的工作。用户当然是空的,因为尚未发生认证。 –

2

What am I doing wrong?

可能[Authorize]属性重写您的更改。因此,而不是在WindowsAuthentication_OnAuthenticate方法这样做你Global.asax编写自定义Authorize属性,就像这样:

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

,然后使用您的自定义,而不是属性的默认之一:

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

在ASP。 NET MVC执行授权的标准方式是通过授权操作过滤器,而不是通过Global.asax中的事件。

+0

授权属性不会覆盖您的上下文。 –

+1

无论如何,在'Global.asax'中使用事件来执行ASP.NET MVC应用程序中的授权是个不好的做法。您应该使用自定义授权过滤器。 –

+1

他没有在他的代码中进行授权,他只是应用了自己的自定义主体,该参数仍应在global.asax中完成。 –