Read-only user permissions in MVC3 application with minimal changes

I have the task of creating a read-only user for our ASP.Net MVC3 application. That is, they can log in, view all the data, but they cannot update the data.

I read a lot of authentication articles / frameworks, for example: Embed secure ASP.NET MVC applications or Free security configuration or Create action filters in ASP.Net MVC (and several others, I already lost links).

The problem with most approaches requiring radical changes in the domain / application. And to carry out this function, I have only one day .

We have about a hundred controllers, an average of 4 actions per controller (mainly CRUD operations), and through each of them there can be no question. It would also be easy to forget to add attributes to the new code - to introduce errors.

So far, I have come up with a global filter that negates all POST-based actions and controller actions called "Create" for a read-only user:

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
    }
}

The next thing I plan to create the [AllowReadOnlyUser] attribute for post-actions, for example, changing the password / email and filter, allows this action to pass.

I wonder if there are better ways to do such things?

Update: The application is not for public consumption. It is used in the corporate world to track people, assets, and other boring data.

2. , . , . , .

+5
2

System.Web.Mvc.AuthorizeAttribute . , AuthorizeAttribute AuthorizeCore HandleUnauthorizedRequest. AuthorizeCore , , HandleUnauthorizedRequest , , (, "NotAllowed" -View).

, . , POST-. POST-, , .

+4

, , - , 100% , . , . , .

, jQuery ajax - , .

, , :

if (isReadonly && !Page.ClientScript.IsClientScriptBlockRegistered("ReadonlyScriptController"))
{
this.Page.ClientScript.RegisterStartupScript(this.GetType(), 
  "ReadonlyScriptController", "<script>RunReadonlyScript();</script>");
}

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>
+1

All Articles