[翻译] ASP.NET MVC Framework控制器操作安全性
原文地址:http://gridviewguy.com/Articles/385_ASP_NET_MVC_Framework_Controller_Action_Security.aspx
翻译:Anders Liu
摘要:ASP.NET MVC Framework允许开发者使用更为灵活的方式创建Web应用程序。使用MVC框架可以摆脱令人头疼的ViewState和Postback,还能让应用程序便于测试。在这篇文章中,我们将研究控制器操作的基于角色的安全性。
Introduction
简介
ASP.NET MVC Framework allows the developers to build their web application in a more flexible way. Using MVC framework you by passes the headaches of ViewState and Postbacks and also enable your application for testing. In this article we are going to take a look at the Controller Action Role-Based Security.
ASP.NET MVC Framework允许开发者使用更为灵活的方式创建Web应用程序。使用MVC框架可以摆脱令人头疼的ViewState和Postback,还能让应用程序便于测试。在这篇文章中,我们将研究控制器操作的基于角色的安全性。
Prerequisite
前提
If this is your first encounter with ASP.NET MVC Framework then I strongly suggest that you check out the introductory article using the link below:
如果你第一次接触ASP.NET MVC Framework,我强烈建议你通过下面的链接看一下对它的介绍:
Getting Started with the ASP.NET MVC Framework
Scenario
场景
The scenario is really simple. A list of categories is displayed on the page and when the user clicks on the category it will be deleted. But we need to make sure that the user is authorized to delete the items.
这个场景非常简单。页面上会显示一系列分类,当用户单击分类时,对应的分类会被删除。但我们需要确保用户已被授权,能够删除其中的项。
Populating the Page with List of Categories
生成分类列表页面
The first task is to populate the page with a list of categories. Let’s see how this can be implemented.
第一个任务是生成包含分类列表的页面。我们看看这是如何实现的。
[ControllerAction] public void List() { NorthwindDataContext northwind = new NorthwindDataContext(); var list = northwind.Categories; RenderView("Categories", list); }The List action is responsible for populating the Categories view with the required data. Let’s check out the Categories view.
List操作负责生成显示所需数据的Categories视图。我们来看一下Categories视图。
public partial class Categories : ViewPage> { } (c => c.Delete(category.id), category.CategoryName, new { onclick = "return confirmDelete(" + category.id + ")" })%>The first thing to note is the Categories class inherits from the ViewPage which is of IEnumerable<Category> type. This means that we will have the strong type support for IEnumerable<Category> in the HTML view of the page. Now, let’s discuss the HTML part of the Categories view.
第一个要注意的是Categories类继承自用于IEnumerable<Category>的ViewPage类。这意味着在页面的HTML视图中,我们将得到对IEnumerable<Category>的强类型支持。接下来,我们讨论Categories视图的HTML部分。
The foreach loop is used to iterate through the categories. The Html.ActionLink method is used to create hyperlinks which are directed to particular controllers. The first argument to the Html.ActionLink is the Linq expression for the action. The argument c => c.Delete(category.id) means that we are attaching the Delete action to all the categories in the ViewData object. The Delete operation will take a single parameter which is categoryId. The next parameter is the text to appear for the hyperlink. The final parameter is the HTML attributes. We are using onclick attribute of the hyperlink which will popup a confirmation box.
foreach循环用于迭代分类。Html.ActionLink方法用于创建指向特定控制器的超链接。传给Html.ActionLink的第一个参数是与其操作对应的Linq表达式。参数c => c.Delete(category.id)表示附加到ViewData对象中的所有分类的Delete操作。Delete操作携带一个参数categoryId。下一个参数是要显示成超链接的文字。最后一个参数是HTML属性。我们使用超链接的onclick属性弹出一个确认框。
The HTML generated for the page might look something like this:
为该页面生成的HTML看起来象下面这样:
Beverages EditeCondiments
Confections
Dairy Products
Now, looking at the URL’s above anyone can easily delete the item by simply copying the URL in the address bar. So, the question is how do we secure the controller actions so only authorized users would be able to delete the items.
现在来看一下上面的URL,任何人都可以通过将URL复制到地址栏来删除其中的项。那么,我们如何来确保控制器操作的安全性,使得只有已授权的用户能够删除其中的项呢?
Controller Action Security
控制器操作安全性
ASP.NET MVC Framework is still in its development phases and there is still a lot on the wish list. Maybe in few months the framework will provide us the flexibility to configure action based security easily.
ASP.NET MVC Framework仍处在开发过程中,目标列表中还有很多东西。也许几个月后这个框架就能为我们带来灵活的、简单的、基于操作的安全性。
For now let’s use another approach to add security to our controller actions. The OnPreAction event is fired before the action is executed and this seems to be an ideal place to authorize the user. You can override the OnPreAction of the controller class but this solution is not scalable since then you will need to override all the controllers for security purposes. A better approach is to introduce a BaseController and override the OnPreAction of the BaseController. All the controllers will derive from the BaseController class instead of the Controller class. And the BaseController will derive from the Controller class.
目前,我们只能通过其他途径为控制器操作添加安全性。OnPreAction事件会在操作执行前触发,看起来是个放置用户授权的好地方。你可以重写控制器类的OnPreAction方法,但这中解决方法不具可伸缩性,因为出于安全的目的你需要重写所有控制器。更好的方法是引入一个BaseController并重写BaseController的OnPreAction方法。所有的控制器都从BaseController继承,而不再是Controller类。而BaseController类是从Controller类继承而来的。
protected override bool OnPreAction(string actionName, System.Reflection.MethodInfo methodInfo) { string controllerName = methodInfo.DeclaringType.Name; if(!IsAuthorized(controllerName,actionName)) throw new SecurityException("not authenticated"); return base.OnPreAction(actionName, methodInfo); }The IsAuthorized custom method is responsible for performing the actual authorization.
IsAuthorized自定义方法负责执行具体的授权。
private bool IsAuthorized (string controllerName, string actionName) { System.Web.HttpContext context = System.Web.HttpContext.Current; XDocument xDoc = null; if (context.Cache["ControllerActionsSecurity"] == null) { xDoc = XDocument.Load(context.Server.MapPath("~/ControllerActionsSecurity.xml")); context.Cache.Insert("ControllerActionsSecurity",xDoc); } xDoc = (XDocument) context.Cache["ControllerActionsSecurity"]; IEnumerable elements = xDoc.Element("ControllerSecurity").Elements(); var role = (from e in elements where ((string)e.Attribute("controllerName")) == controllerName && ((string)e.Attribute("actionName")) == actionName select new { RoleName = e.Attribute("Roles").Value }).SingleOrDefault(); if (role == null) return true; if (!User.IsInRole(role.RoleName)) return false; return true; }Nothing too complicated! The authorization details are stored in an XML file called ControllerActionsSecurity.xml. Here are the contents of the file:
一点也不复杂!授权的详细信息存放在一个名为ControllerActionSecurity.xml的XML文件中。下面是该文件的内容:
- controllerName: The name of the controller
- actionName: The action of the controller
- Roles: Authorized roles
- controllerName——控制器的名字
- actionName——控制器的操作
- Roles——授权的角色
If you need to add authorization to a different controller then simply make an entry in the XML file with the appropriate controllerName and the actionName.
如果你需要为另一个控制器添加授权,只许用适当的controllerName和actionName在这个XML文件中创建一个入口即可。
Conclusion
小结
In this article we learned how to authorize the user based on the controller and the action. Hopefully, ASP.NET team will introduce more flexible ways to authorize the users based on their actions.
在这篇文章中,我们学到了如何基于控制器和操作为用户授权。希望ASP.NET团队能够为基于操作的用户授权引入更为灵活的方式。
I hope you liked the article happy coding!
希望你能喜欢这篇文章,编码快乐!
此处下载源代码:http://gridviewguy.com/ArticleDownloads/AspAllianceMVC_a.zip。