我的任务是为ASP.Net MVC3应用程序创建只读用户。即他们可以登录,查看所有数据,但无法更新任何数据。
我已经阅读了很多身份验证文章/框架,例如:Implement secure ASP.NET MVC applications,Fluent Security Configuration或Creating Action Filters in ASP.Net MVC(以及其他一些,我已经丢失了链接)
大多数方法的问题是它们需要对域/应用程序进行重大更改。我只有一天来实现该功能。
我们有大约一百个控制器,每个控制器平均有4个动作(主要是CRUD操作),并且经历每一个控制器是不可能的。此外,很容易忘记在新代码上添加属性 - 引入错误。
到目前为止,我已经提出了全局过滤器,它拒绝所有基于POST的操作和称为“创建”的控制器操作为只读用户:
public class ReadOnlyFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext filterContext)
{
var currentUser = HttpContext.Current.User;
if (currentUser == null || !currentUser.Identity.IsAuthenticated)
return; // user is not logged in yet
if (!currentUser.IsInRole("Readonly"))
return; // user is not read-only. Nothing to see here, move on!
// Presume User is read-only from now on.
// if action is of type post - deny
if (filterContext.HttpContext.Request.HttpMethod.ToUpper() == "POST")
{
filterContext.HttpContext.Response.Redirect("~/ReadOnlyAccess");
}
// if action is "Create" - deny access
if (filterContext.ActionDescriptor.ActionName == "Create")
{
filterContext.HttpContext.Response.Redirect("~/ReadOnlyAccess");
}
// if action is edit - check if Details action exits -> redirect to it.
//TODO get this done ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
return;
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
// blah! have to have this here for IActionFilter
}
}
接下来我计划为后期操作创建属性[AllowReadOnlyUser],例如更改密码/电子邮件,并在过滤器中允许该操作通过。
我想知道是否有更好的方法来做这种事情?
更新:该应用程序不供公众使用。它在企业界用于跟踪人员,资产和其他无聊的数据。
更新2 :我似乎完成了这项任务。将其作为控制器完成,就像启动一样。完整代码和一些解释can see in my blog。
答案 0 :(得分:4)
您可以将System.Web.Mvc.AuthorizeAttribute用于您的目的。创建一个派生自AuthorizeAttribute的类,并覆盖AuthorizeCore和HandleUnauthorizedRequest方法。在AuthorizeCore中,您确定是否允许用户执行操作,在HandleUnauthorizedRequest中,如果不允许,则确定要显示的内容(例如,显示“NotAllowed”-View)。
创建自定义授权属性后,必须将该属性添加到应受自定义授权保护的所有控制器操作。例如,所有POST方法。但是,如果应该允许所有用户使用POST方法,则只需将该属性添加到该控制器操作中。
答案 1 :(得分:1)
你必须稍微调整一下,在任何人告诉我之前我100%意识到这是一个可怕的黑客。但它也非常有效并且很快实施,这是当时最重要的问题。你当然希望通过一个障碍物来运行它。
还有一些更新面板内容必须被删除,或者更改为jQuery ajax响应结束挂钩或类似的东西,如果需要。
哦,有这个控制只为只读用户运行它:
if (isReadonly && !Page.ClientScript.IsClientScriptBlockRegistered("ReadonlyScriptController"))
{
this.Page.ClientScript.RegisterStartupScript(this.GetType(),
"ReadonlyScriptController", "<script>RunReadonlyScript();</script>");
}
脚本:
<script type="text/javascript" src="<%# Page.ResolveUrl("~/ClientScripts/jquery-1.4.2.min.js") %>"></script>
<script type="text/javascript">
function RunReadonlyScript() {
//Extend jquery selections to add some new functionality
//namely, the ability to select elements based on the
//text of the element.
$.expr[':'].textEquals = function (a, i, m) {
var match = $(a).text().match("^" + m[3] + "$");
return match && match.length > 0;
};
//this function does all the readonly work
var disableStuff = function () {
//select all controls that accept input, save changes, open a popup, or change form state
// ** customize this with your own elements **
$('button, input:not(:hidden), textarea, select,
a:textEquals("Clear Selection"),
a:textEquals("Add Message"),
a:textEquals("CCC EVAL"),
a[id$="availLink"],
a[id$="lbtnDelete"],
a[id$="lbtnEdit"]')
//disable input controls
.attr('disabled', 'disabled')
//remove onclick javascript
.removeAttr('onclick')
//remove all bound click events
.unbind("click")
//add a new click event that does nothing
//this stops <a> links from working
.click(function (e) {
e.preventDefault();
return false;
});
//zap some images with click events that we don't want enabled
$('img[id$="imgCalendar1"], img[id$="imgDelete"]').hide();
}
//if we are loading the home page, don't disable things
//or the user won't be able to use the search controls
var urlParts = document.URL.split('/');
var last2 = urlParts[urlParts.length - 2] + '/' + urlParts[urlParts.length - 1];
if (last2 !== 'home/view') {
//disable everything initially
disableStuff();
//setup a timer to re-disable everything once per second
//some tab panels need this to stay disabled
setInterval(disableStuff, 1000);
//some pages re-enable controls after update panels complete
//make sure to keep them disabled!
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(disableStuff);
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(disableStuff);
}
}
</script>