如何在asp.net-mvc控制器中集中授权逻辑?
我有一个ASP.NET-MVC网站,带有SQL Server后端。我有许多控制器操作需要我进行权利检查 现在,我这样做:如何在asp.net-mvc控制器中集中授权逻辑?,asp.net,asp.net-mvc,asp.net-mvc-4,asp.net-mvc-5,entitlements,Asp.net,Asp.net Mvc,Asp.net Mvc 4,Asp.net Mvc 5,Entitlements,我有一个ASP.NET-MVC网站,带有SQL Server后端。我有许多控制器操作需要我进行权利检查 现在,我这样做: public ActionResult SomeEntitledPage() { if (_myModel.IsMySiteAdminRole) { return View(new MyViewModel()); } else { r
public ActionResult SomeEntitledPage()
{
if (_myModel.IsMySiteAdminRole)
{
return View(new MyViewModel());
}
else
{
return View("NotEntitled", new NotEntitledViewModel(){Page = "[PageName]", SupportDG = "support@support.com"});
}
}
这很好,但感觉就像我在很多地方复制了这个逻辑
基于以下内容,使多个授权控制器操作“安全”的最佳方式(属性等)是什么
(安全性在于它检查IsMystiteAdminRole
,如果未授予权限,则返回“未授予权限”视图
我还想确保我没有在每个页面上都有性能损失?实现这一点的最佳方法是使用属性并用它装饰操作 看看 您可以继承它并执行自己的自定义逻辑。以下是我刚才做的一个项目的示例:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class AuthorizeAttribute : System.Web.Mvc.AuthorizeAttribute
{
public bool AdminRequired;
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (UserSession.IsLoggedIn)
return (!AdminRequired || (AdminRequired && UserSession.IsAdmin));
else
return false;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary
{
{ "action", "LogIn" },
{ "controller", "Account" },
{ "returnUrl", filterContext.HttpContext.Request.RawUrl}
});
}
}
使用此属性,您可以拥有两个级别的授权:普通用户和管理员用户。示例:
[Authorize(AdminRequired = true)]
public ActionResult AdminOnlyAction()
{
// perform authorized admin tasks
}
[Authorize]
public ActionResult RegularUserAction()
{
// perform authorized regular user action
}
我更喜欢对权限/特权逻辑使用操作过滤器。这些过滤器的优点是,它们可以在操作方法填充模型后运行 例如:
public class AdminOnlyFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (!filterContext.Controller.ViewData.Model.IsMySiteAdminRole)
{
filterContext.Result = new ViewResult
{
ViewName = "NotEntitled",
Model = new NotEntitledViewModel(){Page = "[PageName]", SupportDG = "support@support.com"}
};
}
base.OnActionExecuted(filterContext);
}
}
动作过滤器允许您有选择地覆盖控制器的OnActionExecuted
方法
此属性可以应用于特定操作或整个控制器。结果将取决于您的模型值,并且只会更改您的视图。我同意这里的其他人的看法,即您可以使用属性来完成此操作,但我只想指出另一种替代方法。您可以编写一个基本控制器,所有c需要权限检查的控制器继承。在该控制器中,您可以编写逻辑来检查权限:
public class BaseController : Controller
{
private readonly bool _isEntitled;
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
// Your logic for entitlement check goes here.
// Set _isEntitled to true if user is entitled to view page.
}
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!_isEntitled) {
// Redirect user which is not entitled.
filterContext.Result = new ViewResult
{
ViewName = "NotEntitled",
Model = new NotEntitledViewModel(){Page = "[PageName]", SupportDG = "support@support.com"}
};
}
}
}
现在,您所要做的就是在需要进行授权检查的所有控制器中继承此控制器:
public MyController : BaseController
{
// Action in here...
}
我并不是说这是一个更好的选择,我只是指出了一种做你需要的事情的替代方法。此外,如果你想确保权限检查不会在每个页面请求上发生,而只在用户登录时发生一次…TL;DR:
查看扩展您的用户配置文件,并在用户通过身份验证时用角色信息填充它
在我看来,问题似乎源于安全层的设计,因为您正在检查的用户只在错误的执行阶段可用,这导致了这种复杂性。看起来您试图做的是检查发出请求的用户,看看他是否满足特定的角色要求,并向他们显示一个u未经授权的页面,如果它们不符合要求(漂亮的教科书内容),但由于某些原因,该用户位于视图模型中,并且该视图模型在控制器完全实例化之前不会生成,这意味着您无法检查它是否在管道中初始化。草率的解决方案是覆盖控制器上的initialize方法,调用base方法,但在基本初始化为c之后执行一些工作完成。那么你的数据应该准备好了。但那太草率了
一般来说,您的会话用户应该以UserProfile或扩展标识的形式出现在会话中。通过这样做,您可以填充该用户的角色以及其他角色,然后在控制器/操作执行管道的任何阶段对其进行检查;然后您可以使用自定义属性检查user.IsInRole(“任意”)。您不需要该操作来返回“未授权”视图,因为您可以在“授权”属性HandlUnauthorizedRequest override的响应中设置该视图。我同意其他人建议的解决方案 您提到的是,您需要在需要检查模型IsInAdminRole属性的任何位置复制代码。因此,我创建了一个通用方法,用于传递模型和viewname/path。在ISENTITED方法中,只需检查isadminrole属性并采取必要的措施 注意:这只是一个简单的示例解决方案。您可以检查这是否有帮助或提供一些提示 做如下事情 样本模型
public class NoRights
{
public string Message { get; set; }
}
public class MyModel
{
public bool IsAdminRole { get; set; }
}
这是家庭控制器
public class HomeController : Controller
{
public ActionResult Index()
{
var mod = new MyModel() { IsAdminRole = true };
return IsEntitled(mod, "IndeX");
//return View();
}
}
这是一个示例静态方法,可以放在helper类中。
注意:这将返回一个标准错误视图,其中包含在NoRights
模型的message属性中指定的错误消息
public static ViewResult IsEntitled(object model, string viewPath)
{
var prop = model.GetType().GetProperty("IsAdminRole");
var hasRights = (bool)prop.GetValue(model, null);
var viewResult = new ViewResult();
if (hasRights)
{
viewResult.ViewData = new ViewDataDictionary(model);
viewResult.ViewName = viewPath;
}
else
{
viewResult.ViewData = new ViewDataDictionary(
new NoRights() { Message = "Your dont have rights" });
viewResult.ViewName = "Error";
}
return viewResult;
}
如果我在IsAdminRole
属性中传递true,这里就是输出
如果我在IsAdminRole
属性中传递false,我将得到以下输出
希望这能有所帮助。我们有一个类似的案例,要求将授权逻辑完全设置在一个集中的位置。为此,您可以尝试类似的方法 首先,您可以有一个应用程序级控制器,它可以
public class ApplicationController : Controller
{
protected override void OnActionExecuted(ActionExecutedContext ctx)
{
base.OnActionExecuted(ctx);
if (!_myModel.IsMySiteAdminRole)
{
ctx.Result = View("NotEntitled", new NotEntitledViewModel(){Page = "[PageName]", SupportDG = "support@support.com"});
}
}
}
现在此控制器可以在其他控制器中继承。您的整个授权逻辑现在集中在一个控制器中
public class EntitlementController: ApplicationController
{
return View(new MyViewModel());
}
我只需要在一个特定的控制器中执行此操作(它有一个对“model”类的引用,该类可以告诉我用户是否有权使用该函数。我如何将其注入到该控制器中,以便调用“\u myModel.ismysteadminrole”在AuthorizeCore方法中?我不认为放置在控制器操作上的属性可以感知该操作的控制器。您可以尝试“搜索”对于传递的
httpContext
。我的建议是将\u myModel.ismysteadminrole
提取到一个类中,该类知道可以从属性访问的httpContext
。在我的示例中,UserSession
是一个静态类,其属性使用httpContext.Current.Session
存储va当前用户的lues。我不希望每个控制器中的每个操作都被授予权限。这只是一些控制器中的一些操作。您的答案如何满足