0

I'm quite new with ASP so be tolerant :)

I've got a view with a search form in it.

View

<div id="search-form" class="row search-form">
    @using(Ajax.BeginForm("Search",
    "Home",
    new AjaxOptions
    {
        UpdateTargetId = "result",
        InsertionMode = InsertionMode.Replace,
        LoadingElementId = "ajax_loader"
    },
    new { @class = "form-horizontal col-sm-offset-3 col-sm-6" }
    ))
    {
        <div class="form-group">
            <div class="col-sm-10">
                @{string query = string.Empty;}
                @Html.EditorFor(x => query, new { htmlAttributes = new { @class = "form-control" } })
            </div>
            <input id="submitbtn" type="submit" value="Search" class="btn btn-primary col-sm-2" />
        </div>
    }
</div>

<div id="ajax_loader" style="display:none">
    <img src="~/Content/Images/ajax_loader.gif" alt="Ajax Loader" />
</div>
<div id="result"></div>

Controller

[AllowAnonymous]
public ActionResult Index()
{
   ViewBag.Title = "serach form";
   return View();
}

public async Task<ActionResult> Search(string query)
{
   WinesApiController winesCtrl = new WinesApiController();
   var listOfWines = await winesCtrl.Get(query);
   return PartialView("_WineResult", listOfWines);
}

The Search method in my controller returns a PartialView. When I decorate all the methodsin the controller with the [AllowAnonymous] attribute, everything works very well. But what I would like it to display the form for anybody, but as long as you click on the search button, you need to be logged in. So I deleted all the AllowAnonymous attributes but on the Index method (the one which render my View). Now, the result of my call is not shown anymore (which is quite ok) but I am not redirected to the login view.

My question is then, why the call to the partial view does not redirect me to the login view ? I guess that authentification is performed because I cannot see the results of the submit action, but why am I not redirected ?

GuillaumeA
  • 3,493
  • 4
  • 35
  • 69
  • decorate `Search` with `[Authorize]` attribute – Mike Debela Jun 05 '15 at 16:34
  • As I said, it does not work. My application is globally secured with a global authorization filter anyway. – GuillaumeA Jun 05 '15 at 17:16
  • I could be wrong (I don't use `Ajax.BeginForm`) but based on your code above, it seems that the "result" (response) is being sent back to your Ajax call - you'd probably need to inspect the response to your XHR and redirect client side as needed... – EdSF Jun 05 '15 at 17:28
  • @EdSF. I'm not sure I understand your point, but when I disable all Authorization needs, the Ajax call update my view by pushing the partial view in the #result div as expected. – GuillaumeA Jun 05 '15 at 17:41
  • Yes, because the result of your XHR _suceeded_ (result is/are returned). You could probably check with browser dev tools and inspect the XHR request and response and see if there are any HTTP errors (e.g. 401). – EdSF Jun 05 '15 at 17:44
  • [This](http://stackoverflow.com/questions/743252/how-may-i-best-use-the-authorize-attribute-with-ajax-and-partial-views) seems relevant to what I'm referring to... – EdSF Jun 05 '15 at 17:46
  • Ok I see ! But as mentioned in the post you refered to, no 401 status is sent when calling for the partial view. I will explore... – GuillaumeA Jun 05 '15 at 18:16
  • 1
    @EdSF Thanks for your input. I used [this](http://stackoverflow.com/questions/5258721/authorize-attribute-and-jquery-ajax-in-asp-net-mvc?lq=1) post to solve my issue. Furthermore, I needed to add the attribute as a global filter instead of the Mvc one because even using the attribute did not override the default behavior. – GuillaumeA Jun 05 '15 at 19:34

2 Answers2

0

You are making an ajax call to the Search Action right? The default asp.net mvc AuthorizeAttribute does not return an appropriate response when authorization fails on ajax calls. You could write your own Authorization Filter, that returns a better response, like this:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public sealed class YourAuthorizeAttribute : AuthorizeAttribute {

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) {

        var httpContext = filterContext.HttpContext;
        var request = httpContext.Request;
        var response = httpContext.Response;

        if (request.IsAjaxRequest()) {
            response.SuppressFormsAuthenticationRedirect = true;
            response.StatusCode = (int)HttpStatusCode.Unauthorized;
            response.End();
        }

        base.HandleUnauthorizedRequest(filterContext);
    }
}

With this filter, you could have a default javascript code to handle all unauthorized scenarios:

$.ajaxSetup({
    statusCode: {
        401: function (response) {
            var returnUrl = encodeURI(window.location.pathname + window.location.search);
            var loginUrl = '/custumer/login?ReturnUrl=' + returnUrl;

            window.location.href = loginUrl;
        }
    }
});
-1

What happens if you put an Authorize attribute on the action?

[Authorize()]
public async Task<ActionResult> Search(string query)
{
   WinesApiController winesCtrl = new WinesApiController();
   var listOfWines = await winesCtrl.Get(query);
   return PartialView("_WineResult", listOfWines);
}
Phil
  • 1,609
  • 12
  • 24