MVC5中无法访问自定义IPrincipal

时间:2015-10-19 17:21:40

标签: c# asp.net asp.net-mvc-5 asp.net-identity windows-authentication

我已经阅读了很多关于这个主题的问题和答案,但没有一个能帮助我解决这个问题。

我遇到的问题是HttpContext.Current.UserUser属性的类型为RolePrincipal,而不是我的自定义主体。

这是一个使用Windows身份验证(仅限Intranet的应用程序)的MVC 5 Web应用程序。我的自定义主体是WindowsPrincipal的子类,我确实实现了自己的RoleProvider以用于Authorize属性标记。

当我尝试通过在当前HttpContext上从IPrincipal将其转换为我的自定义主体来使用主体时,我收到一条错误,指出它的类型为RolePrincipal,显然无法将其转换为我的自定义主要。我在Application_PostAuthenticationRequest事件中设置我的自定义主体:

protected void Application_PostAuthenticationRequest(object sender, EventArgs e)
{
    if (User == null)
        return;

    using(EntityContext db = new EntityContext ())
    {
        var user = db.Users.SingleOrDefault(u => u.ADName.Equals(User.Identity.Name));
        HttpContext.Current.User = new PcsPrincipal((WindowsIdentity)User.Identity, user);
    }
}

当我在该方法中设置断点时,它似乎永远不会被调用,这可以解释为什么它没有被设置为我的自定义主体。

我已经审核了以下质量检查,但他们无法解决此问题:

如果没有设置Principal,我做错了什么?如果需要发布更多代码,请告诉我。

编辑:在WindowsAuthentication.OnAuthenticate事件中将HttpContext.Current.User设置为我的自定义主体不能解决此问题。使用该方法表现出完全相同的行为。

2 个答案:

答案 0 :(得分:1)

您应该在应用程序验证当前请求时发生的WindowsAuthentication_OnAuthenticate事件中设置自定义主体。

protected void WindowsAuthentication_OnAuthenticate(object source, WindowsAuthenticationEventArgs e)
{   
    using(EntityContext db = new EntityContext ())
    {
        var user = db.Users.SingleOrDefault(u => u.ADName.Equals(e.Identity.Name));
        HttpContext.Current.User = new PcsPrincipal(e.Identity, user);
    }
}

答案 1 :(得分:1)

在不断研究这个问题之后,我终于通过另一个SO问题找到了答案,使我的问题有点重复:MVC3 Windows Authentication override User.Identity

以下是@Toby Jones发布的答案(作为对原始问题的编辑),这导致我解决了我的问题,但他的回答实际上是@Erik Funkenbusch& amp; @Darin Dimitrov。编辑答案是为了解决一些语法和问题。删除一些多余的信息。

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

不应使用Application_AuthenticateRequest事件,因为(即使启用了Windows身份验证,HttpContext.Current.User为空)用户尚未在Windows身份验证过程中填充,因此我无法使用任何内容来获取用户信息。

Application_AuthorizeRequest是链中的下一个,在WindowsIdentity被引入后发生。

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

选项2:覆盖AuthorizeAttribute

以下是授权属性的覆盖

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

然后将所有AuthorizeAttributes替换为自定义版本。

选项1全局处理所有内容,而选项2使用过滤器处理更加个性化的所有内容。

就个人而言,我选择使用global.asax方法,因此我可以在全球范围内使用自定义主体。这是解决我的问题的实际代码:

protected void Application_AuthorizeRequest(object source, EventArgs e)
{
    if(User.Identity.IsAuthenticated && Roles.Enabled)
    {
        using (EntityContext db = new EntityContext ())
        {
            var user = db.Users.Include("Roles").SingleOrDefault(u => u.ADName.Equals(User.Identity.Name));
            if (user == null)
                return;

        PcsPrincipal principal = new PcsPrincipal((WindowsIdentity)User.Identity, user);
            Context.User = principal;
        }
    }            
}