我有一个管理区域,我只希望管理员能进入该区域。我考虑在管理区域的每个控制器中添加Authorized属性。是否有更优雅的解决方案或者框架本身没有这个功能?
编辑: 很抱歉,我之前应该提到。我正在使用从AuthorizeAttribute派生出来的自定义AuthorizedAttribute。
我有一个管理区域,我只希望管理员能进入该区域。我考虑在管理区域的每个控制器中添加Authorized属性。是否有更优雅的解决方案或者框架本身没有这个功能?
编辑: 很抱歉,我之前应该提到。我正在使用从AuthorizeAttribute派生出来的自定义AuthorizedAttribute。
基于 Web.config 的安全性在 MVC 应用程序中几乎永远不应该被使用。原因是多个 URL 可能会命中一个控制器,在 Web.config 中设置这些检查通常会漏掉某些情况。请记住 - 控制器与区域无关,路由与区域相关联。如果没有冲突,MVC 控制器工厂将很高兴地为非区域请求提供 Areas/ 文件夹下的控制器。
例如,使用默认项目结构,在 AdminDefaultController 中添加一个 Admin 区域,您可以通过 /Admin/AdminDefault/Index 和 /AdminDefault/Index 两种方式访问该控制器。
唯一支持的解决方案是将属性放在控制器基类上,并确保该区域内的每个控制器都是该基类的子类。
我刚刚调查了这个同样的问题。由于无法根据区域来保护控制器,因此想到了一个更简单的选择。
为每个区域创建一个基本控制器定义来覆盖Controller,并将安全性要求添加到此控制器中。然后,您只需要确保该区域中的每个控制器都是继承自AreaController而不是Controller即可。例如:
/// <summary>
/// Base controller for all Admin area
/// </summary>
[Authorize(Roles = "Admin")]
public abstract class AdminController : Controller { }
仍需要从此基础派生Admin区域中的每个控制器,
public class HomeController : AdminController
{
// .. actions
}
但至少你有一个单一的点来定义该区域的安全性。
[Authorize]
属性的问题相同。解决方案在这里并没有错。 - Quango我刚开始做这个...但目前来看,这对我而言运作得相当不错。
我创建了一个自定义的AuthorizeAttribute类,并将其添加到RegisterGlobalFilters函数中。
在CustomAuthorizeAttribute中,我根据它所在的区域检查各种条件。
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new CustomAuthorizeAttribute());
filters.Add(new HandleErrorAttribute());
}
}
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var routeData = httpContext.Request.RequestContext.RouteData;
var controller = routeData.GetRequiredString("controller");
var action = routeData.GetRequiredString("action");
var area = routeData.DataTokens["area"];
var user = httpContext.User;
if (area != null && area.ToString() == "Customer")
{
if (!user.Identity.IsAuthenticated)
return false;
}
else if (area != null && area.ToString() == "Admin")
{
if (!user.Identity.IsAuthenticated)
return false;
if (!user.IsInRole("Admin"))
return false;
}
return true;
}
}
如果您所有的管理员代码都在一个控制器中,则将Authorize添加到整个类中。
[Authorize]
public class AdminController : Controller
{
.......
}
AuthorizeAttribute
的 Inherited
属性已设置为 true
,因此只需继承它。https://msdn.microsoft.com/zh-cn/library/system.web.mvc.authorizeattribute(v=vs.118).aspx - Mikael Dúi Bolinderpublic static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
...
//Deny access to all controllers and actions so that only logged in Administrators can access them by default
filters.Add(new System.Web.Mvc.AuthorizeAttribute() { Roles = "Administrator" });
}
[OverrideAuthorization]
和[Authorize]
进行装饰。Index()
的Get和Post方法。public class MarkupCalculatorController : Controller //Just continue using the default Controller class.
{
// GET: MarkupCalculator
[OverrideAuthorization]
[Authorize(Roles = "Administrator,Dispatcher")]
public ActionResult Index()
{
//Business logic here.
return View(...);
}
// POST: DeliveryFeeCalculator
[HttpPost]
[ValidateAntiForgeryToken]
[OverrideAuthorization]
[Authorize(Roles = "Administrator,Dispatcher")]
public ActionResult Index([Bind(Include = "Price,MarkedupPrice")] MarkupCalculatorVM markupCalculatorVM)
{
//Business logic here.
return View(...);
}
}
示例2 - 仅允许经过身份验证的用户访问Home控制器的Index()
方法。
public class HomeController : Controller
{
[OverrideAuthorization]
[Authorize] //Allow all authorized (logged in) users to use this action
public ActionResult Index()
{
return View();
}
}
示例 3 - 可以使用 [AllowAnonymous]
属性允许未经身份验证的用户(即匿名用户)访问方法。这也会自动覆盖全局过滤器,无需使用 [OverrideAuthorization]
属性。
// GET: /Account/Login
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
//
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
...
}
示例 4 - 只有管理员才能访问缺少 [Authorize]
属性的方法。
public class LocationsController : Controller
{
// GET: Locations
public ActionResult Index()
{
//Business logic here.
return View(...);
}
}
一些注意事项。
如果您想限制特定角色访问特定操作,则必须使用[OverrideAuthorization]
属性。否则,[Authorize]
属性将被忽略,只允许默认角色(例如我的示例中的管理员),即使您指定其他角色(例如Dispatcher等),也因为全局过滤器而被允许。任何未经授权的用户都将被重定向到登录屏幕。
使用[OverrideAuthorization]
属性会导致操作忽略您设置的全局过滤器。因此,每次使用覆盖时,您必须重新应用[Authorize]
属性,以确保操作的安全性。
关于整个区域和控制器
如您所询问的,要限制区域,请在控制器上放置[OverrideAuthorization]
和[Authorize]
属性,而不是单个操作。
AuthorizeAreaFolder
一起使用对我很有帮助:services.AddRazorPages()
.AddRazorPagesOptions(options => options.Conventions.AuthorizeAreaFolder("Admin", "/"))
.WithRazorPagesAtContentRoot();
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AdminPolicy", policy => policy.RequireRole("Administrator"));
});
builder.Services.AddRazorPages(options =>
{
options.Conventions.AuthorizeAreaFolder("Identity","/Account/Manage", "AdminPolicy");
});
..我相信你想要的是类似这样的东西吧?
[Authorize(Roles = "Admins")]
public ActionResult Register()
{
ViewData["roleName"] = new SelectList(Roles.GetAllRoles(), "roleName");
ViewData["PasswordLength"] = MembershipService.MinPasswordLength;
return View();
}