MVC3 Аутентификация Windows переопределяет User.Identity

Я создаю приложение intranet, используя MVC3 с бэкэнд MSSQL. У меня есть проверка подлинности и роли (через поставщика настраиваемых ролей), работающих должным образом. То, что я пытаюсь сделать сейчас, - это переопределить User.Identity, чтобы разрешить такие элементы, как User.Identity.FirstName. Но я не могу найти код, который покажет мне, как это сделать в WindowsIdentity

Я пробовал написать пользовательский поставщик:

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, а не мой пользовательский принцип. Что я делаю неправильно?

EDIT:

Я прокомментировал код выше в global.asax.  Я переопределил 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;
    } 

}

И скорректировал мой принцип следующим образом:

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]
    • Идентичность

Идентификация доступна; однако он все еще является WindowsIdentity CPrincipal доступен только в часах и недоступен напрямую.

EDIT: Спасибо всем, кто внес свой вклад в это. Вы значительно расширили мое понимание того, как работают различные части.

У меня есть оба способа работы, поэтому я думал, что поделюсь.

Вариант 1: переопределить запрос авторизации в Global.asax

Это тот, с которым я иду.

Я не использовал Application_AuthenticateRequest, потому что (в соответствии с этим: HttpContext.Current.User имеет значение null, даже если аутентификация Windows включена), пользователь не был заполнен в Процесс проверки подлинности Windows и, следовательно, я ничего не могу использовать, чтобы получить информацию о пользователе.

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

Это переопределение Принципала

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 обрабатывает все в глобальном масштабе, вариант 2 обрабатывает все на индивидуальном уровне.

Ответ 1

Вместо этого вы должны переопределить метод Application_AuthenticateRequest в global.asax, а затем использовать 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 или всего, что мне нужно. Это не ракетостроение, и оно работает.

Ответ 2

Что я делаю неправильно?

Вероятно, атрибут [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.