MVC3 Windows Authentication переопределить User.Identity

Я строю приложение для интрасети, используя 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; }
}

и переопределение аутентификации Windows для заполнения пользовательского принципала.

    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]
    • тождественность

Идентичность доступна; Тем не менее, это все-таки WindowsIdentity CPrincipal доступен только в часы и не доступны напрямую.

РЕДАКТИРОВАТЬ: Спасибо всем, кто способствовал этому. Вы значительно расширили мое понимание того, как работают различные части.

Я получил оба способа работы, поэтому я решил поделиться.

Вариант 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);
    }
}

Вот переопределение атрибута Authorize

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

2 ответа

Решение

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

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

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