简体   繁体   English

MVC3 Windows身份验证覆盖User.Identity

[英]MVC3 Windows Authentication override User.Identity

I am building a intranet application using MVC3 with a MSSQL backend. 我正在使用带有MSSQL后端的MVC3构建Intranet应用程序。 I have authentication and roles (through a custom roles provider) working properly. 我有身份验证和角色(通过自定义角色提供程序)正常工作。 What I am trying to do now is overriding User.Identity to allow for items like User.Identity.FirstName. 我现在要做的是重写User.Identity以允许像User.Identity.FirstName这样的项目。 But I cannot find any code that will show me how do this in WindowsIdentity 但我找不到任何代码可以告诉我在WindowsIdentity中如何做到这一点

I have tried writing a custom provider: 我试过写一个自定义提供程序:

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

and overriding the WindowsAuthentication to populate the custom principal. 并覆盖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;
        }
    }

I have a breakpoint in the authentication function and the principal is being populated; 我在身份验证功能中有一个断点,并且正在填充主体; however, when I put a breakpoint in the controllers, the User is just its normal RolePrincipal, instead of my custom principal. 但是,当我在控制器中放置一个断点时,User只是它的正常RolePrincipal,而不是我的自定义主体。 What am I doing wrong? 我究竟做错了什么?

EDIT: 编辑:

I commented out the code above in the global.asax. 我在global.asax中注释掉了上面的代码。 I have overridden the AuthorizeAttribute using C#: 我使用C#覆盖了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;
    } 

}

And adjusted my principal to the following: 并将我的校长调整为以下内容:

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

Now I when I put a breakpoint in, the watch shows the following in user: 现在,当我放入断点时,手表会在用户中显示以下内容:

  • User 用户
    • [CSupport.Model.CPrincipal] [CSupport.Model.CPrincipal]
    • Identity 身分

Identity is accessable; 身份是可访问的; however, it is still the WindowsIdentity CPrincipal is only accessible in the watch and not accessible directly. 但是,它仍然是WindowsIdentity CPrincipal只能在手表中访问,不能直接访问。

EDIT: Thanks to everyone who contributed to this. 编辑:感谢所有为此做出贡献的人。 You have greatly expanded my understanding of how the various parts work. 您已经大大扩展了我对各个部分如何工作的理解。

I got both ways to work, so I thought I would share. 我有两种工作方式,所以我想我会分享。

Option 1: Override the Authorize Request in Global.asax 选项1:覆盖Global.asax中的授权请求

This is the one I am going with. 这是我要去的那个。

I did not use Application_AuthenticateRequest because (according to this: HttpContext.Current.User is null even though Windows Authentication is on ) the user has not been populated in a Windows authentication process and thus there is nothing that I can use to go get the user information. 我没有使用Application_AuthenticateRequest,因为(根据这个: 即使启用Windows身份验证,HttpContext.Current.User为null )用户还没有在Windows身份验证过程中填充,因此没有什么可以用来获取用户信息。

Application_AuthorizeRequest is the next in the chain and happens after the windows identity is brought in. Application_AuthorizeRequest是链中的下一个,在引入Windows标识后发生。

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

This is the override of the Principal 这是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);
    }
}

This is how you access the updated info in the new Principal that was created. 这是您在创建的新Principal中访问更新信息的方法。

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

Option 2: Override the AuthorizeAttribute 选项2:覆盖AuthorizeAttribute

This is the overridden Principal (It is the same as above) 这是被覆盖的校长(与上面相同)

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

Here is the override of the Authorize Attribute 这是授权属性的覆盖

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

}

This is where you change which AuthorizeAttribute to use and utilizing the new information. 您可以在此处更改要使用的AuthorizeAttribute并使用新信息。

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

Option 1 handles everthing globally, option 2 handles everything at an individual level. 选项1处理全局覆盖,选项2处理单个级别的所有内容。

Instead of doing it this way, you should override the Application_AuthenticateRequest method in global.asax, then use Current.User rather than HttpContext.Current.User (not sure why, but there is a difference). 你不应该这样做,而应该覆盖global.asax中的Application_AuthenticateRequest方法,然后使用Current.User而不是HttpContext.Current.User(不知道为什么,但是有区别)。

Then, an easy way to access this in your controller is to create an extension method? 那么,在控制器中访问它的一种简单方法是创建一个扩展方法? Something like this: 像这样的东西:

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

then you can just say User.Identity.IMyIdenty().FirstName . 然后你可以说User.Identity.IMyIdenty().FirstName You could probably do this as a property as well. 您也许可以将此作为财产。

Here is the code I use: 这是我使用的代码:

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

Now, ignoring the DependencyResolver stuff and the custom auth ticket stuff, this is pretty basic and works correctly for me. 现在,忽略DependencyResolver的东西和自定义身份验证票据,这是非常基本的,对我来说正常。

Then, in my app, when i'm need info from my custom identity, i just cast it with ((IMyIdentity)User.Identity).FirstName or whatever I need. 然后,在我的应用程序中,当我需要来自我的自定义标识的信息时,我只需使用((IMyIdentity)User.Identity).FirstName或我需要的任何内容。 It's not rocket science, and it works. 这不是火箭科学,而是有效的。

What am I doing wrong? 我究竟做错了什么?

Probably the [Authorize] attribute is overriding your changes. 可能[Authorize]属性会覆盖您的更改。 So instead of doing this in the WindowsAuthentication_OnAuthenticate method in your Global.asax write a custom Authorize attribute, like so: 因此,不要在Global.asax中的WindowsAuthentication_OnAuthenticate方法中执行此操作,而是编写自定义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;
    }
}

and then use your custom attribute instead of the default one: 然后使用您的自定义属性而不是默认属性:

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

In ASP.NET MVC the standard way to perform authorization is through authorization action filters, not through events in Global.asax. 在ASP.NET MVC中,执行授权的标准方法是通过授权操作过滤器,而不是通过Global.asax中的事件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM