在我的MVC应用程序中,我有几个不同的角色:管理员,普通用户等等。
我知道我可以通过Authorize属性向我的控制器应用安全性:
[Authorize(Roles="Admin")]
public ActionResult Create()
{
return View();
}
但我还需要对视图应用一些安全性,以便不将View的某些部分显示给某些角色:
@if( User.IsInRole("Admin") )
{
@Html.ActionLink("Create", "Create")
}
以上述方式执行此操作会更好,还是在ViewModel中处理此类安全性:
public ActionResult Index()
{
var model = new IndexViewModel();
model.CanCreate = User.IsInRole("Admin");
return View(model);
}
View:
@( Model.CanCreate )
{
@Html.ActionLink("Create", "Create")
}
第二种方法与第一种方法相比是否有任何好处,还是只是偏好?
答案 0 :(得分:6)
第二种方式更受欢迎,因为您的业务逻辑将保持在模型级别。
在您的示例中,业务逻辑非常简单。但是,想象一下需求已经发生变化,现在不仅管理员可以创建内容,而且还可以创建超过1个月前注册的普通用户。有了业务逻辑,您必须更新所有视图。
答案 1 :(得分:3)
我之前完成此操作的一种方法是创建一个继承自AuthorizeAttribute的动作过滤器。过滤器可以像DisplayIfAuthorizedAttribute一样调用,除了标准的AuthorizeAttribute属性外,还有一个名为ViewNameIfNotAuthorized的属性。
该属性调用base方法进行授权,如果失败,则返回ViewNameIfNotAuthorized视图。否则,它允许action方法正常进行。
然后,您将通过操作方法呈现这些部分视图,并通过父视图中的Html.RenderAction或Html.Action调用操作方法。这些操作方法将使用属性进行修饰。
您现在有一种标准化的方法来执行此操作,并且没有授权代码污染您的操作方法的内部。
这就是过滤器的样子:
public class DisplayIfAuthorizedAttribute : System.Web.Mvc.AuthorizeAttribute
{
private string _ViewNameIfNotAuthorized;
public DisplayIfAuthorizedAttribute(string viewNameIfNotAuthorized = null)
{
_ViewNameIfNotAuthorized = viewNameIfNotAuthorized;
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
bool isAuthorized = base.AuthorizeCore(filterContext.HttpContext);
if (!isAuthorized)
{
filterContext.Result = GetFailedResult();
}
}
private ActionResult GetFailedResult()
{
if (!String.IsNullOrEmpty(_ViewNameIfNotAuthorized))
{
return new ViewResult { ViewName = _ViewNameIfNotAuthorized };
}
else
return new EmptyResult();
}
}
您的操作方法将装饰为:
[DisplayIfAuthorized("EmptyView", Roles="Admin")]
public ViewResult CreateLink()
{
return View("CreateLink");
}
答案 2 :(得分:1)
你可能需要两个......
请注意,仅第二个不安全,用户可能能够在浏览器地址栏中构建actionlink的URL。所以你绝对需要安全属性。
第二个更多的是用户友好性或UI设计。也许您希望用户能够单击“创建”,然后可以选择以不同方式登录。
答案 3 :(得分:0)
检查控制器中的授权,并根据角色的规则为视图准备Viewmodel。
视图用于简单地显示数据。所以,imo,他们不必做角色检查等。
所以准备ViewModel应该有它应该拥有的数据,让View只渲染它。 (你正在使用它的布尔属性就足够了)