这是良好的安全实践把安全相关的属性在ViewModel,在视图中使用,即显示/隐藏"东西"取决于用户的角色?
例如:ViewModel属性AdminRole。在控制器(User.IsInRole)中设置它的值,然后在视图中访问属性:if (Model.AdminRole) {show admin stuff…}
我读过其他SO帖子和(一些)人正在这样做,但质疑这是否安全,即在ViewModel中暴露安全属性。如果有更好、更安全的方法,请告诉我。
离题,但相关:恕我直言,这比呼叫User要好得多。
如果通过"ViewModel"你指的是用于MVC视图的dto(而不是MVVM框架中的ViewModel),那么不,这不是一个好的设计。
首先,从安全角度来看,这是一个糟糕的设计,因为:
-
你依靠你的视图实际上强制安全规则(例如通过检查
AdminRole
有条件地呈现内容)。这很难有效地测试或审查。 -
你冒着无意中泄露私人安全信息给客户端的风险,由于漏洞或只是草率的编码。
-
如果没有适当的卫生处理,您将有可能意外地将此属性用于
POST
,PUT
或其他"写"操作。
但更重要的是,从MVC的角度来看,这是一个糟糕的设计,因为它错过了视图模型应该是什么。
视图模型意味着包含关于如何显示视图的信息。它们应该抽象业务逻辑,否则它们会出现在视图中,而不仅仅是传递给。
对于这种情况,一个更好的设计是这样的:
ViewModel
public class IndexViewModel
{
public bool CanDeleteItems { get; set; }
public bool IsAdminMenuVisible { get; set; }
// Other properties...
}
控制器public ActionResult Index()
{
return View(new IndexViewModel
{
CanDeleteItems = User.IsInRole("ContentManager"),
IsAdminMenuVisible = User.IsInRole("Administrator"),
// Other properties...
});
}
<<p> 视图/strong> @if (Model.IsAdminMenuVisible)
{
<!-- Markup for admin menu -->
}
@foreach (var item in Model.Items)
{
<!-- Markup for item -->
<button type="submit" @((Model.CanDeleteItems) ? "disabled" : "")>Delete</button>
}
这里的想法是ViewModel只包含特定于视图本身的属性。视图不能决定在什么业务条件下某个元素是可见的、禁用的,等等。视图模型将使用以绑定到的特定视图元素命名的属性,准确地告诉该显示什么以及何时显示。
这也有利于可维护性。如果你决定用户应该能够删除项目,如果他们有"ContentManager"或"Administrator"的角色会发生什么?在你的版本中,你最终会修改视图;在上面的版本中,您只需要修改控制器。如果您发现自己不得不修改视图,而不是为了改变外观和感觉,这意味着您在体系结构中犯了一个错误。安全检查应该在控制器中进行。
注意,根据您的体系结构风格,您也可以在ViewModel中实现这些作为派生属性,例如:
public class IndexViewModel
{
private readonly IPrincipal user;
public IndexViewModel(IPrincipal user)
{
this.user = user;
}
public bool CanDeleteItems
{
get { return user.IsInRole("ContentManager"); }
}
public bool IsAdminMenuVisible
{
get { return user.IsInRole("Administrator"); }
}
}
这是一种更面向对象的设计,同样可以接受,因为视图模型实际上并不向视图公开底层规则,并且与控制器一样可测试。就像我上面说的,这更多的是个人偏好的问题,以及你是否希望你的ViewModels是智能的(如MVVM)还是只是愚蠢的dto(更MVC风格)。
如果你的ViewModel被传递到你的动作方法和变量赋值是由模型绑定然后,是的,它可能被劫持使用大规模分配漏洞。如果这是一个问题,我将使用任何其他方法来获取数据到您的视图。
无论您使用哪种方法,您都将使用User.IsInRole
来确定是否应该显示/隐藏"stuff"。
除了您描述的两种方法(设置ViewModel属性或使用User)。IsInRole在视图中直接),我能想到的传递值的唯一其他方法是使用ViewBag, ViewData, Session, Cookie.....所有这些方法的工作原理基本相同。
我怎么做的:
在我的视图开始时,我使用User.IsInRole
,然后将值保存到一个本地属性中,然后在页面中进一步检查以显示/隐藏内容