【发布时间】:2012-12-05 00:11:53
【问题描述】:
在我的 MVC4 应用程序中,有一些操作需要根据您是否登录(在我的情况下为 FormsAuthentication)而采取不同的行为。
例如,我有一个 AccountController,它有一个方法“RenderAccountAndProfile”。如果注销,相应的局部视图会显示登录提示和按钮。如果用户已登录,则会显示用户的个人资料链接以及注销按钮。
到目前为止,我在项目中采用的方法是简单地使用 if 语句...
if (HttpContext.User.Identity.IsAuthenticated)
{
...
}
else
{
...
}
但是,我刚刚创建了一个我认为是这种方法的相当优雅的替代方案。
我创建了一个名为 AnonymousUsersOnly 的新属性,非常简单:
public class AnonymousUsersOnlyAttribute : System.Web.Mvc.ActionMethodSelectorAttribute
{
public override bool IsValidForRequest(System.Web.Mvc.ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
{
return !controllerContext.HttpContext.User.Identity.IsAuthenticated;
}
}
我的 AccountController 类装饰有 Authorize 属性。这使我能够拥有以下代码:
[Authorize]
public class AccountController : Controller
{
[AllowAnonymous]
[AnonymousUsersOnly]
[ActionName("RenderAccountAndProfile")]
public ActionResult RenderAccountAndProfile_Anonymous()
{
// create a "logged out" view model
return Content("**NOT LOGGED IN** - LOG IN HERE");
}
[ActionName("RenderAccountAndProfile")]
public ActionResult RenderAccountAndProfile_Authorized()
{
// create a "logged in" view model
return Content("**LOGGED IN** - LOG OUT");
}
}
我非常喜欢这种方法,因为我的操作方法符合Single Responsibility Principle。每种方法现在只处理登录情况或注销情况。我不再需要任何“if”语句来引导流量。
这也应该使单元测试更容易,因为每个方法现在只关注一个结果,而不是两个。我们可以编写单元测试来分别测试每个结果,调用不同的方法。
显然,我不能有两个具有相同签名的方法,因此我必须使用 ActionName 属性。
我会很感激你在这里的批评。你认为这是一个优雅的解决方案吗?这种方法的优点和缺点是什么?这会带来哪些安全隐患/风险?
【问题讨论】:
-
为什么不直接在action级别使用Authorize属性,让mvc在调用action时检查访问权限,自动带你到登录控制器?
-
这与我想要的功能不太一样。我不希望发生重定向。我在上面创建的是一个过滤器,用于根据用户是否经过身份验证来选择要调用的操作方法。此外,使用 [Authorize] 装饰整个类并使用 [AllowAnonymous] 在其中打孔是一种更安全的方法,因为您不能忘记对所有公共方法应用授权。否则,一个错误就会导致您的整个应用受到威胁。
-
这个的典型用例是装饰呈现部分视图的操作方法,而不是 ViewResults,尽管它当然不限于此。我个人打算使用这种方法来根据用户是否被授权显示不同的内容。
标签: asp.net-mvc asp.net-mvc-3 design-patterns attributes single-responsibility-principle