我正在使用带有MSSQL后端的MVC3构建 Intranet 应用程序。我有身份验证和角色(通过自定义角色提供程序)正常工作。我现在要做的是重写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;
}
}
我在身份验证功能中有一个断点,并且正在填充主体;但是,当我在控制器中放置一个断点时,User只是它的正常RolePrincipal,而不是我的自定义主体。我做错了什么?
修改
我在global.asax中注释掉了上面的代码。 我使用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;
}
}
并将我的校长调整为以下内容:
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();
}
}
现在,当我输入断点时,手表会在用户中显示以下内容:
身份可以访问;但是,它仍然是WindowsIdentity CPrincipal只能在手表中使用,不能直接访问。
修改 感谢所有为此做出贡献的人。您已经大大扩展了我对各部分如何工作的理解。
我有两种工作方式,所以我想我会分享。
选项1:覆盖Global.asax中的授权请求
这是我要去的那个。
我没有使用Application_AuthenticateRequest,因为(根据这个:HttpContext.Current.User is null even though Windows Authentication is on)用户尚未在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);
}
}
这是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);
}
}
这是您访问已创建的新Principal中的更新信息的方式。
[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全局处理everthing,选项2处理单个级别的所有内容。
答案 0 :(得分:6)
您应该覆盖global.asax中的Application_AuthenticateRequest方法,而不是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
或我需要的任何内容。这不是火箭科学,而是有效的。
答案 1 :(得分: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中的事件。