How to handle session expire in partially loaded divs in mvc - asp.net-mvc

I have 2 divs on a page, based on the click id on left i load the content in the right div.
But when session expires, i am expecting the page to redirect to Login, but it does not behave tht way.
some times the button wont work or some times the login screen loads in the right div.
Any suggestions to handle this session expire?

By default, the IIS simply returns the login-page with an HTTP status code 200 when the session is expired. This makes your ajax not see it as an error.
So you need to do a check in your controller action to see whether the Session has expired, and if it has, you can return an HttpStatusCodeResult(HttpStatusCode.Unauthorized).
After that, in your ajax, you can use somthing like this:
$.ajax({
//...
error: function(data, textStatus, xhr) {
if(xhr.status == "401"){ window.location.href = "/login";
}
}

Related

MVC Button Click performs action without redirecting

I have a table where users are allowed to "tick" or "cross" out a row. Ticking a row changes the status value to "Approved" and crossing it changes it to "Disapproved". I'm currently using the Edit scaffold to perform it. How do I do this without having the user being redirected to the view. I just want the user to click it and the page refreshes, with the status value being updated.
I'm not sure what code to post here either since I don't know how to write it. If any part of my program is required, please let me know. I'll include it here. Thank you :>
Add css classes to the 2 buttons "approve-btn" and "reject-btn".
Create javascript function to approve and reject and bind them to
the 2 classes
Create 2 backend functions
Make ajax calls from the JS functions to your backend functions passing the id of the row item
In the "success:" of the ajax call manage the change of the status to show "approved" or "rejected"
To make ajax call you can use the following example (although there are tons of example on google). Since you're modifying data you should use POST call and since it is a POST call, you should add a RequestVerificationToken to prevent CSRF attacks.
function Approve(id){
securityToken = $('[name=__RequestVerificationToken]').val();
$.ajax({
url: '/YourControllerName/Approve/' + itemId,
type: 'POST',
data: {
"__RequestVerificationToken": securityToken
},
success: function (data) {
if (data == 'success')
//use jQuery to show the approved message;
else
alert("something went wrong");
},
error: function (request, err) {
alert("something went wrong");
}
});
}
The Token should be created in the View adding this line:
#Html.AntiForgeryToken()

jQuery Mobile Site using an ajax $.get() to check username availability returning previous page code in return data

I have a simple JQM site I'm working on. I'm trying to validate the availability of a username on the fly in a form. I'm using jquery $.get() ajax to return "success" or "fail" however the return data is being replace with the code of the previous page.
$(document).on('pageinit', function () {
// check to see if username is available
$("#username").change(function() {
$.get("controller.php", { action: "check_username", username: username }, function(data) {
console.log(data);
}
});
The controller.php is checking for availability of the username and return "pass" or "fail" When I do the console.log(data) which I'm expecting to be pass or fail, it's logging out the code from the previous page??
I'm thinking maybe it's a JQM caching issue so I tried to disable cache with no effect. I was orginally using a JQM dialog box to display the form. Thinking that had something to do with it I pulled that out and loaded a straight link. That didn't fix it so I tried to load the page directly using
$.mobile.changePage( "user-new.php", { reloadPage: true});
I am stumped. Why would a $.get ajax call return data be returning code from the previous page?
Here's a face palm! My controller was authenticating and kicking it back out to a login page. Apparently php redirects act funky with ajax return data. Rather then returning the login page code it was returning the previous page code. I Removed the authentication and it works fine. Unbelievable! I'm going to go work at a gas station or something :)

jQuery Mobile Secure Pages

I'm developing a jquery mobile site that is only available to users that are logged in.
I have a function that checks a server for their logged in status:
function checkLogin() {
$(function () {
$.getJSON(root_url + 'manageUsers/checklogin/?callback=?', null,
function (data) {
if (data.logged == 'false') {
$("#index_Container").html("<h2>Login Required</h2></div><p>We've noticed you're not logged in, please login to use this app.</p><p><a href='login.html' data-role='button'>Click here to login</a></p>").trigger('create');
$.mobile.changePage('login.html');
} else {
$(".logged_in").text(data.username);
$(".logged_in").addClass('logout');
$(".header_div").trigger('create');
}
});
});
}
I can't seem to figure out how to implement this so everytime the index page is loaded and any other page loads this is fired prior to rendering anything else on the page. Currently, the page will load and show the HTML, then do $.mobile.changePage('login.html'):
EDIT: If anyone has any ideas on how to implement this in a better way I'd love to know, every page in the app requires the user to be logged in.
In order to have this function run every time you load anew page, you will need to bind it to the pagebeforeload event, and potentially cancel the user navigation if it does not validate the login.
$( document ).bind( "pagebeforeshow", function( event, data ){
event.preventDefault(); //prevents usual load of page
checkLogin(data);
});
You will have to make changes to checkLogin, notably because as the page does not exist yet, so you cannot make changes to the DOM. You can see an quick and dirty example in this fiddle, giving hints as to how do it considering the asynchronous nature of your call.

JSF2 redirect issue

I have login page and dashboard page.
As soon as login process done dashboard page (using navigation rule) will be displayed.
<navigation-rule>
<from-view-id>/login.xhtml</from-view-id>
<navigation-case>
<from-outcome>dashboard</from-outcome>
<to-view-id>/viewp/dashboard.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
I have filter mapping for all requests.
Here is my scenario, There is client side poller on my dashboard page. When server restarts, poller sends request which will be interpreted by Filter.
Inside Filter I have logic like
If(url.contains("login.xhtml))
{
//dofilter
}else
{
// redirect to login.
}
but somehow this is not redirecting.
One observation I have is, after login even though I am on dashboard page, my URL still is like mydomain/login.xhtml. I think because URL in browser is mydomain/login.xhtml, response.redirect("mydomain/login.xhtml") is not working. Any suggestions?
Thank you,
The poller is executed by JavaScript/Ajax, right? Well, you've got to check in JavaScript/Ajax if the server returned a 302 instead of 200 and handle accordingly. The browser itself doesn't do that automatically for returned JavaScript/Ajax responses, but only for responses on synchronous requests.
You can use window.location in JavaScript to perform a "redirect". E.g.
if (ajaxResponseStatus == 302) {
window.location = newURL;
}

MVC3 AntiForgeryToken breaks on Ajax login

ASP.NET MVC's AntiForgeryToken mechanism is based on the current HttpContext.User. It uses that value to construct the token when you call Html.AntiForgeryToken(). Basically it is OK (see an explanation in the last paragraph here) but a problem arises when you log in through an Ajax call.
In my code, when a user logs in, the credentials are sent as a Json object in Ajax (the AntiForgeryToken hidden field value is also sent inside the Json), the server authenticates the user, applies FormsAuthentication.SetAuthCookie(), and returns a Json result which contains some user-specific data. In that way, I can avoid full page refresh upon login.
The problem is that every subsequent Ajax request to the server now fails upon ValidateAntiForgeryTokenAttribute, because it now expects an anti-forgery token that is incompatible with the anti-forgery cookie.
How can I get a valid anti-forgery token to put in the client's hidden field so every Json request after login will succeed?
I tried to get a new hidden-field token manually (using AntiForgery.GetHtml() on the action, extracting the token string itself, returning it to the client in Json and placing it in the anti-forgery hidden field manually in JavaScript) but it does not work - a subsequent Ajax call fails on the ValidateAntiForgeryTokenAttribute on the server.
In fact, every call to AntiForgery.GetHtml() (which is essentially what Html.AntiForgeryToken() helper does) produces a different token, which invalidates the previous one.
I also tried to set HttpContext.User = new GenericPrincipal(new GenericIdentity(email), null); as detailed here, but it doesn't work.
Note: This solution doesn't work for me, because of my specific situation: An Ajax login which changes the user identity on the server and hence every token that was generated before the login is invalid; this solution also doesn't apply because it addresses a different problem.
You will need to clear and redo any existing form token you have upon login. This means your login code will have to either refresh the current page (kinda kills the ajax portion of it eh), your own token implementation, or you will need to refresh your token. It is possible to request a partial view, extract the token, and update your form. You could actually have a restful url which returns nothing but a token to an authenticated user. One may argue this is a security issue, but I don't believe so because it is simply an easier way to get a token rather than requesting any view -partial or otherwise.
You should be able to easily get the token instances to replace via:
var token = $('input[name=""__RequestVerificationToken""]');
EDIT
After re-reading a few more times - I question
Why would you have a token on the form if the user isn't logged in. You allow the same form to be 'operated' while not logged in and logged in? Most sites on the net even in this case will redirect for a login. Am I understanding this correctly? If so, you may want to consider skipping the token here or use a second type of token for unauthenticated users. You I believe are saying an unauthenticated user can already submit something in the application - again if I understand this correctly - without being authenticated.
Ok, what I did was combine the answer from here: jQuery Ajax calls and the Html.AntiForgeryToken() with a partial. I'm using knockout but for those of you not familiar with it you should still be able to follow along pretty easily.
First my html:
<form id="__AjaxAntiForgeryForm" action="#" method="post">#{Html.RenderPartial("AntiForgeryToken");}</form>
<div id="loginTestView">
<button data-bind="visible: signedIn() == false,click: signIn">Sign In</button>
<button data-bind="visible: signedIn, click: signOut">Sign Out</button>
<form>
<button data-bind="click: testToken">Test Token</button>
</form>
</div>
The main difference being that instead of #Html.AntiForgeryToken() I have a AntiForgeryToken partial that contain #Html.AntiForgeryToken().
So to really clarify I now have a AntiForgeryToken.cshtml file with just:
#Html.AntiForgeryToken()
Now when you sign in/out you need to update the token so the javascript/jquery looks like:
$(document).ready(function () {
AddAntiForgeryToken = function (data) {
data.__RequestVerificationToken = $('#__AjaxAntiForgeryForm input[name=__RequestVerificationToken]').val();
return data;
};
var viewmodel = function () {
var vm = this;
vm.signedIn = ko.observable(false);
vm.signIn = function () {
$.post('Home/SignIn', function () {
vm.signedIn(true);
$.get('Home/GetAuthToken', function (newToken) {
$('#__AjaxAntiForgeryForm').html(newToken);
});
});
};
vm.signOut = function () {
$.post('Home/SignOut', function () {
vm.signedIn(false);
$.get('Home/GetAuthToken', function (newToken) {
$('#__AjaxAntiForgeryForm').html(newToken);
});
});
};
vm.testToken = function () {
$.post('Home/TestToken', AddAntiForgeryToken({ stuff: 'stuff' }));
};
};
ko.applyBindings(new viewmodel(), $('#loginTestView')[0]);
});
The main thing to pay attention to here is that the $.get needs to happen after the $.post to signIn/Out. This code could be cleaned up a bit, but that's the main take away. If you don't then since the requests are asynchronous the $.get could (and probably will) come back before you are actually signed in.
That should do it. I haven't run into any other times when the token is updated but it would just require just another call to update the partial.

Resources