授权属性中的角色在 MVC 4 中无法正常工作
Roles in Authorize Attribute does not work as expected in MVC 4
(我是 ASP.NET MVC 4 的新手,在这个项目之前,我习惯于使用 <authentication mode="none">
的 WebForms。
我有一个数据库,我在其中对 ADMIN
和 SUBADMIN
等用户实体具有特定角色。我在我的项目中有单独的控制器来处理不同角色的不同视图,例如 AdminController
和 SubAdminController
我可以根据用户的角色成功地将用户重定向到各自的视图。
我的问题是,当用户登录后,他们甚至可以访问他们无权访问的页面 access.This 这意味着可能是我没有正确设置授权。
我试过什么?
我已经尝试使用 ADMIN 角色过滤器的授权属性,以便只有管理员有权查看相应的视图,例如:
[Authorize(Roles="ADMIN")]
public class AdminController : BaseController
{
....
}
即使用户成功通过身份验证,也会重定向到在 web.config 中配置的登录页面,如下所示:
<authentication mode="Forms">
<forms loginUrl="~/Home/Index" timeout="2880" />
</authentication>
请注意,如果我只是使用 [Authorize]
,那么它可以工作,但即使是 SubAdmin 也可以访问 Admin 视图。
我也试过在 Web.config 中配置授权,如下所示:
<location path="Admin">
<system.web>
<authorization>
<allow roles="ADMIN"/>
<deny users="*"/>
</authorization>
</system.web>
</location>
这导致了与使用 [Authorize(Roles="ADMIN")]
相同的结果。
请注意,如果我安慰出以下内容
User.Identity.ToGenericUserIdentity().RoleName;
在我的 AdminController
然后我得到 ADMIN
我可以在我的操作方法中使用它来重新检查用户实际上是管理员还是子管理员但是在我所有的操作方法中将其写下来作为检查是不正确的。
相关类:
[Serializable]
public class GenericUser
{
public bool IsInRole(string role) { return false; }
public string RoleName { get; set; }
public int UserID { get; set; }
public string UserName { get; set; }
}
[Serializable]
public class GenericUserIdentity : IIdentity
{
private GenericUser genericUser;
private FormsAuthenticationTicket ticket;
public GenericUserIdentity(FormsAuthenticationTicket ticket)
{
var serializer = new JsonSerializer();
var reader = new JsonTextReader(new StringReader(ticket.UserData));
genericUser = serializer.Deserialize<GenericUser>(reader);
this.ticket = ticket;
}
public string AuthenticationType
{
get { return "Custom"; }
}
public bool IsAuthenticated
{
get { return ticket != null; }
}
public string Name
{
get { return genericUser.UserName; }
}
public string RoleName
{
get { return genericUser.RoleName; }
}
public int UserID
{
get { return genericUser.UserID; }
}
}
public static class IdentityExtension
{
public static GenericUserIdentity ToGenericUserIdentity(this IIdentity identity)
{
var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
var ticketInfo = FormsAuthentication.Decrypt(cookie.Value);
return new GenericUserIdentity(ticketInfo);
}
}
我该如何验证?
在显示 Index() 操作登录页面的 HomeController
中,我设置了一个 HttpPost Index 操作,如下所示:
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(string username,string password)
{
UserInformation userInfo = _userProvider.FindUserByName(username);
OrderProvider orderProvider = new OrderProvider(new OrderRepository());
if (userInfo != null && string.Equals(userInfo.Password, password,StringComparison.Ordinal))
{
if (userInfo.isEnabled)
{
GenericUser genericUser = new GenericUser() { UserName = userInfo.Email, UserID = userInfo.UserID, RoleName = userInfo.RoleName };
Response.SetAuthCookie<GenericUser>(genericUser.UserName, genericUser);
if (userInfo.RoleName == "ADMIN")
{
return RedirectToAction("Index", "Admin");
}
else if (userInfo.RoleName == "USER")
{
return RedirectToAction("Index", "Customer");
}
else if (userInfo.RoleName == "DRIVER")
{
return RedirectToAction("Index", "Driver");
}
else if (userInfo.RoleName == "SUBADMIN")
{
return RedirectToAction("Index", "SubAdmin");
}
}
}
ViewBag.Error = true;
return View("Index");
}
编辑
终于覆盖我的自定义属性的 AuthorizeCore
方法对我有用。
public enum Role
{
ADMIN, SUBADMIN, USER, DRIVER
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class AuthorizeUser : AuthorizeAttribute
{
public AuthorizeUser(params object[] roles)
{
if (roles.Any(r => r.GetType().BaseType != typeof(Enum)))
throw new ArgumentException("roles");
this.Roles = string.Join(",", roles.Select(r => Enum.GetName(r.GetType(), r)));
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
var ticketInfo = FormsAuthentication.Decrypt(cookie.Value);
GenericUserIdentity iden = new GenericUserIdentity(ticketInfo);
if (Roles.Contains(iden.RoleName))
return true;
else
return false;
}
}
属性 [Authorize(Roles="ADMIN")]
仅适用于内置角色。
您有自己的 GenericUser.RoleName
,此处不会使用。
您可以编写自己的 MyAuthorize
属性,但首先要非常认真地问问自己,为什么要在这里重新发明轮子。身份和成员资格框架可用并经过测试。当我看到 string.Equals(userInfo.Password, password)
时,我非常怀疑您实施的安全性。
(我是 ASP.NET MVC 4 的新手,在这个项目之前,我习惯于使用 <authentication mode="none">
的 WebForms。
我有一个数据库,我在其中对 ADMIN
和 SUBADMIN
等用户实体具有特定角色。我在我的项目中有单独的控制器来处理不同角色的不同视图,例如 AdminController
和 SubAdminController
我可以根据用户的角色成功地将用户重定向到各自的视图。
我的问题是,当用户登录后,他们甚至可以访问他们无权访问的页面 access.This 这意味着可能是我没有正确设置授权。
我试过什么?
我已经尝试使用 ADMIN 角色过滤器的授权属性,以便只有管理员有权查看相应的视图,例如:
[Authorize(Roles="ADMIN")]
public class AdminController : BaseController
{
....
}
即使用户成功通过身份验证,也会重定向到在 web.config 中配置的登录页面,如下所示:
<authentication mode="Forms">
<forms loginUrl="~/Home/Index" timeout="2880" />
</authentication>
请注意,如果我只是使用 [Authorize]
,那么它可以工作,但即使是 SubAdmin 也可以访问 Admin 视图。
我也试过在 Web.config 中配置授权,如下所示:
<location path="Admin">
<system.web>
<authorization>
<allow roles="ADMIN"/>
<deny users="*"/>
</authorization>
</system.web>
</location>
这导致了与使用 [Authorize(Roles="ADMIN")]
相同的结果。
请注意,如果我安慰出以下内容
User.Identity.ToGenericUserIdentity().RoleName;
在我的 AdminController
然后我得到 ADMIN
我可以在我的操作方法中使用它来重新检查用户实际上是管理员还是子管理员但是在我所有的操作方法中将其写下来作为检查是不正确的。
相关类:
[Serializable]
public class GenericUser
{
public bool IsInRole(string role) { return false; }
public string RoleName { get; set; }
public int UserID { get; set; }
public string UserName { get; set; }
}
[Serializable]
public class GenericUserIdentity : IIdentity
{
private GenericUser genericUser;
private FormsAuthenticationTicket ticket;
public GenericUserIdentity(FormsAuthenticationTicket ticket)
{
var serializer = new JsonSerializer();
var reader = new JsonTextReader(new StringReader(ticket.UserData));
genericUser = serializer.Deserialize<GenericUser>(reader);
this.ticket = ticket;
}
public string AuthenticationType
{
get { return "Custom"; }
}
public bool IsAuthenticated
{
get { return ticket != null; }
}
public string Name
{
get { return genericUser.UserName; }
}
public string RoleName
{
get { return genericUser.RoleName; }
}
public int UserID
{
get { return genericUser.UserID; }
}
}
public static class IdentityExtension
{
public static GenericUserIdentity ToGenericUserIdentity(this IIdentity identity)
{
var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
var ticketInfo = FormsAuthentication.Decrypt(cookie.Value);
return new GenericUserIdentity(ticketInfo);
}
}
我该如何验证?
在显示 Index() 操作登录页面的 HomeController
中,我设置了一个 HttpPost Index 操作,如下所示:
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(string username,string password)
{
UserInformation userInfo = _userProvider.FindUserByName(username);
OrderProvider orderProvider = new OrderProvider(new OrderRepository());
if (userInfo != null && string.Equals(userInfo.Password, password,StringComparison.Ordinal))
{
if (userInfo.isEnabled)
{
GenericUser genericUser = new GenericUser() { UserName = userInfo.Email, UserID = userInfo.UserID, RoleName = userInfo.RoleName };
Response.SetAuthCookie<GenericUser>(genericUser.UserName, genericUser);
if (userInfo.RoleName == "ADMIN")
{
return RedirectToAction("Index", "Admin");
}
else if (userInfo.RoleName == "USER")
{
return RedirectToAction("Index", "Customer");
}
else if (userInfo.RoleName == "DRIVER")
{
return RedirectToAction("Index", "Driver");
}
else if (userInfo.RoleName == "SUBADMIN")
{
return RedirectToAction("Index", "SubAdmin");
}
}
}
ViewBag.Error = true;
return View("Index");
}
编辑
终于覆盖我的自定义属性的 AuthorizeCore
方法对我有用。
public enum Role
{
ADMIN, SUBADMIN, USER, DRIVER
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class AuthorizeUser : AuthorizeAttribute
{
public AuthorizeUser(params object[] roles)
{
if (roles.Any(r => r.GetType().BaseType != typeof(Enum)))
throw new ArgumentException("roles");
this.Roles = string.Join(",", roles.Select(r => Enum.GetName(r.GetType(), r)));
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
var ticketInfo = FormsAuthentication.Decrypt(cookie.Value);
GenericUserIdentity iden = new GenericUserIdentity(ticketInfo);
if (Roles.Contains(iden.RoleName))
return true;
else
return false;
}
}
属性 [Authorize(Roles="ADMIN")]
仅适用于内置角色。
您有自己的 GenericUser.RoleName
,此处不会使用。
您可以编写自己的 MyAuthorize
属性,但首先要非常认真地问问自己,为什么要在这里重新发明轮子。身份和成员资格框架可用并经过测试。当我看到 string.Equals(userInfo.Password, password)
时,我非常怀疑您实施的安全性。