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.