I have an asp application and i need to remove all current session's cookies in the action of logout:
public ActionResult Logout()
{
Upload.Models.CompteModels.Connected = false;
return RedirectToAction("Login", "Account");
}
Now i use a static class CompteModels with a boolean to test if the user is authentifying or not but it's not efficent. so i think that i have to remove all cookies when i logout.
How can i do it?
A static property is shared across all users, so using a static property to determine if a user is logged in will not work correctly, as this would log out all users, or log them in.
You can abandon the session using Session.Abandon or remove a cookie using the HttpResponse.Cookies collection, and write a cookie to it that is expired.
If you mean drop session data and remove the sessions cookies see here for how to do it.
You could create a session variable called LoggedIn or something similar and just clear this in your logout action. Then in your Login action you need to check for this session.
public ActionResult Logout()
{
Upload.Models.CompteModels.Connected = false;
Session.Remove("LoggedIn");
return RedirectToAction("Login", "Account");
}
public ActionResult Login()
{
// check for session var, redirect to landing page maybe?
if(Session["LoggedIn"] == null)
{
RedirectToAction("Home", "Index");
}
else
{
Session.Add("LoggedIn", true);
}
return RedirectToAction("TargetPage", "TargetAction");
}
Just one idea, depends on where you want users to be redirected to and such, TargetPage could be an admin area or something similar.
Related
I'm trying to pass TempData through a couple actions, but I can't get it to persist beyond one pass. I've read a ton of questions on StackOverflow about this, but I just can't get their solutions to work. I know TempData only persists for one redirect, but it is suggested that .Keep() or .Peek() should allow it to persist on another redirect. That unfortunately has not worked for me. I have also tried reassigning TempData and straight hard-coding of TempData from the second redirect and it still will not pass through. I'm obviously missing something. My code:
//First redirect
public ActionResult Index(int? userId, int? reportingYear)
{
if (Session["State"] == null)
{
TempData["Timeout"] = "Your session has timed out. Please login to continue.";
return RedirectToAction("LogOff", "Account");
}
}
//Second redirect
[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
public ActionResult LogOff()
{
//Delete the application cookie and clear session variables
var cookies = Request.Cookies;
List<string> tempCookies = new List<string>();
foreach (string cookie in cookies)
{
if (cookie.ToString() != "quailCoord")
{
tempCookies.Add(cookie);
};
}
foreach (string cookie in tempCookies)
{
HttpCookie deleteCookie = Request.Cookies[cookie];
deleteCookie.Expires = DateTime.Now.AddDays(-1);
Response.Cookies.Add(deleteCookie);
}
Session.Abandon();
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
//When checking that the key exists, it does and enters the if statement to keep the data
if (TempData.ContainsKey("Timeout")
{
TempData.Keep("Timeout");
}
return RedirectToAction("Login");
}
//Third action
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
//It does not find any TempData keys
if (TempData.ContainsKey("Timeout"))
{
ViewBag.Timeout = TempData["Timeout"] as string;
}
return View();
}
I have also attempted these in place of the TempData.Keep("Timeout") method:
TempData.Peek("Timeout")
TempData["Timeout"] = TempData["Timeout"]
TempData["Timeout"] = "Your session has timed out. Please login to continue."
None of these methods pass to the Login() action. TempData is always empty upon entering that action. When debugging, the minute I step over the return RedirectToAction("Login") line, the count in TempData turns to 0. What am I missing? Is deleting the cookies a problem?
Because TempData will store data in Session object which might store SessionId in cookie, if you delete that server will create another SessionId (object) for you instead of the original one.
so that if you want to keep TempData to multiple actions we might need to keep SessionId value from the cookie.
From your code, we can try to add
a judgement to check cookie key whether if yes don't delete the cookie.
foreach (string cookie in cookies)
{
if (cookie.ToString() != "quailCoord" && cookie.ToString() != "ASP.NET_SessionId")
{
tempCookies.Add(cookie);
};
}
In our developing e-commerce solution we are using AspNet Identity 2.2.1 and it is required that any guest (anonymous) users should complete checkout without prior registration to the website. In order to fullfill this requirement have written an ActionFilter named UserMigrationAttribute which obtains SessionTrackId (string GUID) from cookie -which we set from a HttpModule for every request if SessionTrackId is not found along with request cookies- and creates and actual IdentityUser in database with the username something like SessionTrackId#mydomain.com.
We have decorated our BaseController class with this UserMigration attribute in order to utilize its functions throughout the site.
Everything up to this point works as expected with single downside issue, which is when the page is being loaded for the first time for any user, if we try to make an Jquery Ajax Call to a Method which have [ValidateAntiForgeryToken] attribute, the call fails with the 'The provided anti-forgery token was meant for a different claims-based user than the current user.' error, even though we are sending __RequestVerificationToken parameter with every ajax call.
But if user opens another page by clicking link and/or reloads/refreshes current page, all the subsequent ajax calls complete successfully.
In our understanding UserMigrationAttribute creates user on OnActionExecuting method, but after we signIn user in the process #Html.AntiForgeryToken() is not being updated with the right values.
You may find the UserMigrationAttribute code below;
[AttributeUsage(AttributeTargets.Class)]
public class UserMigrationAttribute : ActionFilterAttribute
{
public ApplicationSignInManager SignInManager(ActionExecutingContext filterContext)
{
return filterContext.HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
}
public UserManager UserManager(ActionExecutingContext filterContext)
{
return filterContext.HttpContext.GetOwinContext().GetUserManager<UserManager>();
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
CreateMigrateCurrentUser(filterContext);
base.OnActionExecuting(filterContext);
}
private static readonly object LockThis = new object();
private void CreateMigrateCurrentUser(ActionExecutingContext filterContext)
{
lock (LockThis)
{
var signInManager = SignInManager(filterContext);
var userManager = UserManager(filterContext);
var sessionTrackId = GetSessionTrackId(filterContext);
if (!filterContext.HttpContext.Request.IsAuthenticated)
{
if (!string.IsNullOrEmpty(sessionTrackId))
{
var username = string.Format("{0}#mydomain.com", sessionTrackId);
var user = userManager.FindByName(username);
if (user == null)
{
user = new User() {UserName = username, Email = username};
var result = userManager.Create(user);
userManager.AddToRole(user.Id, StringResources.AnonymousVisitorsGroup);
}
signInManager.SignIn(user, true, true);
}
}
else
{
if (!string.IsNullOrEmpty(sessionTrackId))
{
var username = string.Format("{0}#mydomain.com", sessionTrackId);
var user = userManager.FindByName(username);
if (user != null)
{
if (!HttpContext.Current.User.IsInRole(StringResources.AnonymousVisitorsGroup))
{
var targetUserId = HttpContext.Current.User.Identity.GetUserId<int>();
var service = new Service();
service.Users.MigrateUser(user.Id, targetUserId);
}
}
}
}
}
}
private string GetSessionTrackId(ActionExecutingContext filterContext)
{
var retVal = string.Empty;
if (filterContext.HttpContext.Request.Cookies["stid"] != null)
{
retVal = filterContext.HttpContext.Request.Cookies["stid"].Value;
}
return retVal;
}
}
Any help or suggestions are highly appreciated.
Thank you,
This is happening because the anti-forgery token is set in a cookie, which will not be updated until the next request. If you're manually signing a user in, you should also issue a redirect (even if to the same page they were already headed to), simply to ensure that the cookie data is correct. This normally happens naturally, as the sign in form will redirect to the URL that needed authorization after the user is signed in, thus negating the problem. Since you're not redirecting currently, the data is out of sync.
However, I have to say that this seems like a very poor solution to this particular use case. Creating some sort of temporary-type user and signing that user in to handle guest checkout creates an unnecessary glut of useless data in your database, at best, and leads to bugs and other issues like this one you're experiencing, at worst.
I also run an ecommerce site, and the way we handled guest checkout is incredibly simplistic. The checkout data is just stored in the session (email, shipping/billing address, etc.). We build a view model to handle the actual checkout where the data necessary for submitting the sale comes either from the user object, if they're logged in, or these session variables, if they aren't. If the user is neither logged in, nor has the requisite session variables set, then they are redirected to the onboarding form where billing/shipping, etc. is collected.
For other aspects like maintaining an anonymous cart, we use a permanent cookie with the cart identifier. If the user ends up creating an account, we associate the anonymous cart with their user, and then remove the cookie. This ensures that their cart survives past the session timeout and things like closing the browser, even if they're anonymous.
In other words, in all these things, no user object is actually needed. If it's there (user is logged in), great, we'll use it. Otherwise, we collect and persist the requisite information for checkout via other means.
I have a simple form page, where user can fill some data. After I press post, I need all that data to remain as it is, so if user wants to change data, he/she can. After I save data I store Client object in Session and every time I press Save button, I check if there is user already in Session.
Now I have #Html.ActionLink("New client", "NewUser");, that I press, when I want to create new user. So this link would reload the page and clear that Session.
Note that "New user" should redirect to Index instead, but I managed to get it to work like that, but is not valid way to do so.
Controller code:
public ActionResult Index()
{
return View(_vm);
}
public ActionResult NewUser()
{
Session["newClient"] = null;
return RedirectToAction("Index");
}
clearing the session can only done on backend so you have to make action to clear the session but you dont need return RedirectToAction("Index"); instead return the view
public ActionResult NewUser()
{
Session["newClient"] = null;
return View("Index",_vm);
}
since you are redirecting to the index view for creating new user
On my website, there is a registration form. After having filled this in, the user gets redirected to Azure ACS in order to log in. After having logged in, the user gets redirected back to my website and is to be registered and logged in.
The registration form is submitted by a JavaScript. The information that the user has filled in is saved to a cookie by the RedirectToProvider method in the RegisterController and the user is redirected to ACS. When the user has been redirected back to the website from ACS, the cookie is then read by the RegisterUser method in the RegisterController. The problem is: this works 95% of the time. 5% of the time, the cookie is null when the user comes back. I have been unable to track the cause of this and am wondering if there are any known issues or something that I may have overseen. The form code looks like this:
#using (Html.BeginForm("RedirectToProvider", "Register", FormMethod.Post, new { id = "registerForm" }))
... various fields...
<input type="button" class="btn" id="registerSubmitButton" value="Register" onclick="RegisterRedirect()" />
}
The RegisterRedirect() JavaScript that submits the form (with irrelevant functionality left out here):
var RegisterRedirect = function () {
$("#registerForm").valid();
$("#registerForm").submit();
}
The RedirectToProvider method in the RegisterController:
[AllowAnonymous]
[HttpPost]
public ActionResult RedirectToProvider(RegisterViewModel viewModel)
{
if (ModelState.IsValid)
{
var providerUrl = viewModel.SelectedProviderUrl;
viewModel.SelectedProviderUrl = "";
var json = JsonConvert.SerializeObject(viewModel);
try
{
var cookie = new HttpCookie("RegisterViewModel", json)
{
Expires = DateTime.Now.AddMinutes(10)
};
ControllerContext.HttpContext.Response.Cookies.Add(cookie);
}
catch (FormatException)
{
return RedirectToAction("Index", "Error", new { reason = "Cookie saving error." });
}
return Redirect(providerUrl);
}
return RedirectToAction("Index", "Error", new { reason = "Invalid data. Try again." });
}
The user is redirected to ACS and chooses to log in with, for example, Gmail. ACS calls back to my ClaimsAuthenticationManager (configured in web.config). Afterwards, the method to be called back to (configured in ACS) is called and in turn calls the RegisterUser method that is supposed to read the cookie:
[Authorize]
public ActionResult RegisterUser(User user){
var cookie = ControllerContext.HttpContext.Request.Cookies["RegisterViewModel"];
if (cookie != null){
... registers the user...
}
}
95% of the time, the cookie is not null. 5% of the time, something fails and the cookie is null. The fail rate is higher during the first builds of the website after the Azure Emulator has just started, and lower later on. I have read that it could have something to do with sessions. Does anyone see an obvious error or have any advice? Thanks in advance for any help!
I think that the problem is due to the fact that you sometimes get redirected to a different web role instance where the cookie you created is missing.
I have an asp.net mvc4 application, in which i have to logout from an account :
if (_fonction == "User")
{
if (_is_admin == true) return RedirectToAction("Index");
else
{
Session["user"] = _u;
return RedirectToAction("Index", "User");
}
}
in the controller User
public ActionResult Index()
{
if (Session["user"] == null) return RedirectToAction("Index", "Home");
return View(Session["user"]);
}
the action Logout
public ActionResult Logout()
{
if (_is_admin) { Session["user"] = null; return RedirectToRoute("Administration"); }
else { Session["user"] = null; return RedirectToAction("Index", "Home"); }
}
i do this : i log in to a user account then i disconnect so i'am in the home page , then i click into the back button of the browser i got the page of the account. When i refresh i returned to the home page. i think that the problem is in the cache and i don't think that make it null is a good idea .
So how can i fix this problem?
You can try to add [OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")] as an attribute to your User controller's Index action to force non-cached results.
But I would strongly suggest to just use AuthorizeAttribute because this will prevent unauthorized web requests done on a specific view. The benefit of using this is that you still give the users the liberty to cache your views and be secured at the same time.
if you do not want to clean your cache then below is the javascript which helps you to hard refresh your page on click of the browser back button
if (window.name != "") { // will be '' if page not prev loaded
window.name = ""; // reset to prevent infinite loop
window.location.reload(true);
}
window.name = new Date().getTime();
put the above "javascript" code on your page. so, it will hard refresh your page.