Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Orchard CMS Ajax Anti-Forgery Token When Logged In

I am building an Orchard CMS module that I am testing on an Orchard 1.3.10 site. The module displays a details view for one of my entities and I have a "favorites" button that I would like to click and do an ajax post to a controller action to save the entity as a favorite in the database.

On the view I have the following code:

<div style="padding: 10px;">
    <span data-id="@Model.Id" id="addFavorite" style="cursor: pointer;">
    [Add Favorite]
    </span>
</div>

<script type="text/javascript">
    $("#addFavorite").click(function () {
        alert("here we go...");
        $.ajax({
            type: "post",
            dataType: "",
            url: "/orchardlocal/mymodule/stuff/AddFavorite",
            data: { id: $(this).data("id") },
            success: function (response) {
                alert("it worked");
            }
        });
    });
</script>

My controller action is...

[HttpPost]
public ActionResult AddFavorite(int id)
{
    return View();
}

When I run the site without being logged into Orchard, this code posts back just fine. If I log in and click on Add Favorite, I get this exception...

A required anti-forgery token was not supplied or was invalid.

System.Web.Mvc.HttpAntiForgeryException was unhandled by user code Message=A required anti-forgery token was not supplied or was invalid. Source=System.Web.WebPages ErrorCode=-2147467259 WebEventCode=0 StackTrace: at System.Web.Helpers.AntiForgeryWorker.Validate(HttpContextBase context, String salt) at System.Web.Helpers.AntiForgery.Validate(HttpContextBase httpContext, String salt) at System.Web.Mvc.ValidateAntiForgeryTokenAttribute.OnAuthorization(AuthorizationContext > filterContext) at Orchard.Mvc.AntiForgery.AntiForgeryAuthorizationFilter.OnAuthorization(AuthorizationContext filterContext) in C:\Code\OrchardDev2\src\Orchard\Mvc\AntiForgery\AntiForgeryAuthorizationFilter.cs:line 37 at System.Web.Mvc.ControllerActionInvoker.InvokeAuthorizationFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor) at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) InnerException:

Why does it treat the post differently when logged in and not?

How can I supply an anti-forger token to avoid this?

Thanks, Brian

like image 847
Brian Behm Avatar asked Jan 27 '12 05:01

Brian Behm


2 Answers

ASP.NET MVC doesn't support the generation of raw anti-forgery tokens by default. Fortunately Orchard provides an extension method for that.

You can simply change your ajax call as is:

$.ajax({
    type: "post",
    dataType: "",
    url: "/orchardlocal/mymodule/stuff/AddFavorite",
    data: { 
        id: $(this).data("id") },
        __RequestVerificationToken: '@Html.AntiForgeryTokenValueOrchard()'
    },
    success: function (response) {
        alert("it worked");
    }
});

This technique is useful as you don't need an existing FORM on your page. Though this solution is only valid if the javascript is rendered from a Razor view.

There is still a solution if you have a separate script file from your view, which is to save the anti-forgery token inside a javascript variable declared from the view, then use it from the script:

@using(Script.Head()) {
<script type="text/javascript">
//<![CDATA[
    var antiForgeryToken = '@Html.AntiForgeryTokenValueOrchard()';
//]]>
</script>
}

Then from the script:

data: { 
    id: $(this).data("id") },
    __RequestVerificationToken: antiForgeryToken 
}

If not, then the solution proposed by Darin would be he correct approach.

like image 73
Sébastien Ros - MSFT Avatar answered Sep 28 '22 02:09

Sébastien Ros - MSFT


How can I supply an anti-forger token to avoid this?

This will depend on where the hidden field containing the anti forgery token is located on the page. For example:

$("#addFavorite").click(function () {
    var token = $(':input[name="__RequestVerificationToken"]').val();
    $.ajax({
        type: "post",
        dataType: "",
        url: "/orchardlocal/mymodule/stuff/AddFavorite",
        data: { 
            __RequestVerificationToken: token,
            id: $(this).data("id") 
        },
        success: function (response) {
            alert("it worked");
        }
    });
});
like image 38
Darin Dimitrov Avatar answered Sep 28 '22 01:09

Darin Dimitrov