InitializeCulture change language of domain - c#

I have a MasterPage with a combo with languages, the thing is that I would like to assign a default language the moment a user starts the application, after that the user can change between languages. What I understand is that I have to override InitializeCulture method on all of the pages, the problem is, where I can save the selected language? When I use Cache["Culture"] all of the user that starts the application shares the same Cache and overrides the value for all the users logged in.
How can I do that? or how can I save data for a single user's thread when it's not logged in?
Thanks in advance for any help.

use the Session object for data specific to sessions, if you need to persist the choice beyond the session you will need to store it with whatever user data you have
Session["Culture"] = yourculturevar;

If you want to save information locally to a user's computer (as opposed to saving something in a database on the server for logged in users), you can use cookies.
Setting a Cookie
private void SetLanguageCookie(string language)
{
HttpCookie cookie = new HttpCookie("UserSelectedLanguage", language);
// Optionally set expiration for cookie
cookie.Expires = DateTime.Now.AddDays(30);
}
Retrieving a Cookie
private string GetLanguageCookie()
{
HttpCookie cookie = Request.Cookies["UserSelectedLanguage"];
return cookie.Value;
}

Related

MVC logout all active sessions after same user login

I have c# mvc web application.There is simple login page according to email and password. Now I have a need like that:
When a user login to the system, all active sessions that same email address will logout.
How can I achieve this?
You can use Session.Abandon() or Clear() to abandon the current session, but if there are multiple people logged in with the same address, this will not address that.
You'd have to build that detection in; for instance, you could update a flag on the table that represents your users and then in the other user's sessions periodically check the table if they were re-logged in. OR when a user logs in, create a token in a database table with an expiration date; associate that token to a user in a cookie. When logged out or logging back in, you could invalidate the token associated to that email address, and each user, when they attempt to access the application, could be rejected by your application checking whether the token is expired.
The Abandon method should work (MSDN):
Session.Abandon();
If you want to remove a specific item from the session use (MSDN):
Session.Remove("YourItem");
If you just want to clear a value you can do:
Session["YourItem"] = null;
If you want to clear all keys do:
Session.Clear();
If none of these are working for you then something fishy is going on. I would check to see where you are assigning the value and verify that it is not getting reassigned after you clear the value.
Simple check do:
Session["YourKey"] = "Test"; // creates the key
Session.Remove("YourKey"); // removes the key
bool gone = (Session["YourKey"] == null); // tests that the remove worked

Storing Check Box Selection in Cookies

I have programmed a Remember Me check box to store the username and password in cookies if the box is checked. My problem is, that if they check it and then re-launch the application the username and password auto fill, but the checkbox does not stay checked.
I have not figured out a way to do this yet...
I will post my code below:
if (!IsPostBack)
{
if (Request.Cookies["UserName"] != null && Request.Cookies["Password"] != null)
{
userNameTxtBox.Text = Request.Cookies["UserName"].Value;
passwordTxtBox.Attributes["value"] = Request.Cookies["Password"].Value;
}
}
if (chkBoxRememberMe.Checked)
{
Response.Cookies["UserName"].Expires = DateTime.Now.AddDays(30);
Response.Cookies["Password"].Expires = DateTime.Now.AddDays(30);
}
else
{
Response.Cookies["UserName"].Expires = DateTime.Now.AddDays(-1);
Response.Cookies["Password"].Expires = DateTime.Now.AddDays(-1);
}
Response.Cookies["UserName"].Value = myUserName
string passwordEncrypted = Crypto.Sha256(myPassword);
Response.Cookies["Password"].Value = passwordEncrypted;
The above code works as it should. But I have a remember me check box that if it is checked I would like to save it to the cookies and leave it checked until the user unchecks it....
Any ideas?
If the checkbox should be checked by default any time the cookie is present, then I imagine you can just set its checked state here:
if (Request.Cookies["UserName"] != null && Request.Cookies["Password"] != null)
{
userNameTxtBox.Text = Request.Cookies["UserName"].Value;
passwordTxtBox.Attributes["value"] = Request.Cookies["Password"].Value;
chkBoxRememberMe.Checked = true; // <-- here
}
Note that there are probably a couple of problems you're overlooking here...
If you always check the checkbox by default when the cookie is present, you don't give the user any way to uncheck the checkbox. The user would need to manually delete the cookie from their browser, which isn't a very great user experience. (Not to mention many users won't be aware of how to do that.)
Storing a user's password in plain text is grossly irresponsible. Please stop doing that immediately. Instead, generate some kind of unique token to identify the user and store that token in the cookie. The server-side code would then validate the token against known tokens associated with known users. Never, ever store the user's password in plain text anywhere.
Not only is what you're doing terribly bad in terms of security, you're also reinventing the wheel.
ASP.Net already supports out of the box Forms authentication, a default membership provider, properly encrypted/hashed authentication cookies and even a logon control with a remember me checkbox!
You would add the control to your ASP.Net logon page with markup something like this:
<asp:Login ID="LoginControl1" runat="server" CreateUserUrl="Register.aspx"
VisibleWhenLoggedIn="False" TextLayout="TextOnTop" RememberMeSet="True">
(We've set the DisplayRememberMe property to true. This instructs the logon control to display the "Remember me next time" check box and the membership provider to send the persistent authentication cookie to the user's browser upon successful logon.)
Before you start trying that however you should probably read "Walkthrough: Creating a Web Site with Membership and User Login" on MSDN.

Set proxy user in a GenericPrincipal, while keeping the old identity, using MVC

I have a site where I allow some users to proxy in as an other user. When they do, they should see the entire site as if they where the user they proxy in as. I do this by changing the current user object
internal static void SetProxyUser(int userID)
{
HttpContext.Current.User = GetGenericPrincipal(userID);
}
This code works fine for me.
On the site, to proxy in, the user selects a value in a dropdown that I render in my _layout file as such, so that it appears on all pages.
#Html.Action("SetProxyUsers", "Home")
The SetProxyUsers view looks like this:
#using (#Html.BeginForm("SetProxyUsers", "Home")) {
#Html.DropDownList("ddlProxyUser", (SelectList)ViewBag.ProxyUsers_SelectList, new { onchange = "this.form.submit();" })
}
The controller actions for this looks like this
[HttpGet]
public ActionResult SetProxyUsers()
{
ViewBag.ProxyUsers_SelectList = GetAvailableProxyUsers(originalUserID);
return PartialView();
}
[HttpPost]
public ActionResult SetProxyUsers(FormCollection formCollection)
{
int id = int.Parse(formCollection["ddlProxyUser"]);
RolesHelper.SetProxyUser(id);
ViewBag.ProxyUsers_SelectList = GetAvailableProxyUsers(originalUserID);
return Redirect(Request.UrlReferrer.ToString());
}
All this works (except for the originalUserID variable, which I put in here to symbolize what I want done next.
My problem is that the values in the dropdown list are based on the logged in user. So, when I change user using the proxy, I also change the values in the proxy dropdown list (to either disappear if the "new" user isn't allowed to proxy, or to show the "new" user's list of available proxy users).
I need to have this selectlist stay unchanged. How do I go about storing the id of the original user? I could store it in a session variable, but I don't want to mess with potential time out issues, so that's a last resort.
Please help, and let me know if there is anything unclear with the question.
Update
I didn't realize that the HttpContext is set for each post. I haven't really worked with this kind of stuff before and for some reason assumed I was setting the values for the entire session (stupid, I know). However, I'm using windows authentication. How can I change the user on a more permanent basis (as long as the browser is open)? I assume I can't use FormAuthentication cookies since I'm using windows as my authentication mode, right?
Instead of faking the authentication, why not make it real? On a site that I work on we let admins impersonate other users by setting the authentication cookie for the user to be impersonated. Then the original user id is stored in session so if they ever log out from the impersonated users account, they are actually automatically logged back in to their original account.
Edit:
Here's a code sample of how I do impersonation:
[Authorize] //I use a custom authorize attribute; just make sure this is secured to only certain users.
public ActionResult Impersonate(string email) {
var user = YourMembershipProvider.GetUser(email);
if (user != null) {
//Store the currently logged in username in session so they can be logged back in if they log out from impersonating the user.
UserService.SetImpersonateCache(WebsiteUser.Email, user.Email);
FormsAuthentication.SetAuthCookie(user.Email, false);
}
return new RedirectResult("~/");
}
Simple as that! It's been working great. The only tricky piece is storing the session data (which certainly isn't required, it was just a nice feature to offer to my users so they wouldn't have to log back in as themselves all the time). The session key that I am using is:
string.Format("Impersonation.{0}", username)
Where username is the name of the user being impersonated (the value for that session key is the username of the original/admin user). This is important because then when the log out occurs I can say, "Hey, are there any impersonation keys for you? Because if so, I am going to log you in as that user stored in session. If not, I'll just log you out".
Here's an example of the LogOff method:
[Authorize]
public ActionResult LogOff() {
//Get from session the name of the original user that was logged in and started impersonating the current user.
var originalLoggedInUser = UserService.GetImpersonateCache(WebsiteUser.Email);
if (string.IsNullOrEmpty(originalLoggedInUser)) {
FormsAuthentication.SignOut();
} else {
FormsAuthentication.SetAuthCookie(originalLoggedInUser, false);
}
return RedirectToAction("Index", "Home");
}
I used the mvc example in the comments on this article http://www.codeproject.com/Articles/43724/ASP-NET-Forms-authentication-user-impersonation to
It uses FormsAuthentication.SetAuthCookie() to just change the current authorized cookie and also store the impersonated user identity in a cookie. This way it can easily re-authenticate you back to your original user.
I got it working very quickly. Use it to allow admin to login as anyone else.

Changing expiry on ASP.NET's Session State cookie

I'm using ASP.NET Session State to keep track of logged in users on my site.
However, one problem I'm running into is that by default ASP.NET session cookies are set to expire when the browser closes.
http://ahb.me/43e
I've tried setting my own ASP.NET_SessionId cookie and modifying the cookie's expiry using something similar to the following code:
Response.Cookies["ASP.NET_SessionId"].Expires = DateTime.Now.AddMonths(1);
None of these approaches work, they all set a second cookie with the same name.
Is there a way of changing the session cookie's expiry?
Based on links in Joe's answer, I figured out this approach:
public void Application_PostRequestHandlerExecute(object sender, EventArgs e)
{
UpdateSessionCookieExpiration();
}
/// <summary>
/// Updates session cookie's expiry date to be the expiry date of the session.
/// </summary>
/// <remarks>
/// By default, the ASP.NET session cookie doesn't have an expiry date,
/// which means that the cookie gets cleared after the browser is closed (unless the
/// browser is set up to something like "Remember where you left off" setting).
/// By setting the expiry date, we can keep the session cookie even after
/// the browser is closed.
/// </remarks>
private void UpdateSessionCookieExpiration()
{
var httpContext = HttpContext.Current;
var sessionState = httpContext?.Session;
if (sessionState == null) return;
var sessionStateSection = ConfigurationManager.GetSection("system.web/sessionState") as SessionStateSection;
var sessionCookie = httpContext.Response.Cookies[sessionStateSection?.CookieName ?? "ASP.NET_SessionId"];
if (sessionCookie == null) return;
sessionCookie.Expires = DateTime.Now.AddMinutes(sessionState.Timeout);
sessionCookie.HttpOnly = true;
sessionCookie.Value = sessionState.SessionID;
}
This code can be inserted in Global.asax.cs.
I would suggest you use FormsAuthentication to track logged in users. You can use a persistent FormsAuthenticationCookie to achieve what you want.
Or if you really want to use Session State, try this technique.
Just a guess: Maybe editing the session.configuration inside the web.config could change the cookie-expiration? You can take a look here?
I think trying to keep session alive for a long time is the wrong approach and limits your scalability. The session cookie is pointing to a specific session that's being maintained by IIS on the server. In general, you want session to close after the user closes their browser so as to not consume all of the available server resources for inactive users. You want session for a departing user to close and the resources made available to a new arriving user. That's why the session cookie expires.
If you want to maintain some user state after the user closes their browser, you can always look at something like Profile. Or, if this is for something like a shopping cart, you can persist your shopping cart in a database and then reconnect that to the user when they log on again.
Tom's answer almost worked for me, except for casting the cookie into a variable and setting its properties. I had to set the properties of the object directly like so:
HttpContext.Current.Response.Cookies["ASP.NET_SessionId"].Expires = expiryDate;
HttpContext.Current.Response.Cookies["ASP.NET_SessionId"].HttpOnly = true;
HttpContext.Current.Response.Cookies["ASP.NET_SessionId"].Value = sessionState.SessionID;
I still cast the cookie into a variable to check if it's null, and return if so.

FormsAuthentication after login

Ok, i have simple scenario:
have two pages:
login and welcome pages.
im using FormsAuthentication with my own table that has four columns: ID, UserName, Password, FullName
When pressed login im setting my username like:
FormsAuthentication.SetAuthCookie(userName, rememberMe ?? false);
on the welcome page i cant use:
Page.User.Identity.Name
to provide to user which user currently logged, BUT i dont user username like at all examples in http://asp.net web site i want to user FullName field
i think that always go to db and request fullname when page loads its crazy and dont like to user Sessions or Simple Cookie mayby FormsAuth provider has custom fields for this
I would store the user's full name in the session cookie after your call to FormsAuth
FormsAuth.SetAuthCookie(userName, rememberme);
// get the full name (ex "John Doe") from the datbase here during login
string fullName = "John Doe";
Response.Cookies["FullName"].Value = fullName;
Response.Cookies["FullName"].expires = DateTime.Now.AddDays(30);
and then retrieve it in your view pages via:
string fullName = HttpContext.Current.Request.Cookies["FullName"].Value
Forms authentication works using cookies. You could construct your own auth cookie and put the full name in it, but I think I would go with putting it into the session. If you use a cookie of any sort, you'll need to extract the name from it each time. Tying it to the session seems more natural and makes it easy for you to access. I agree that it seems a waste to go back to the DB every time and I would certainly cache the value somewhere.
Info on constructing your own forms authentication cookie can be found here.
Sorry I'm a little late to the party, but here's how you can do this without storing the value anywhere else :)
var authCookieKey = FormsAuthentication.FormsCookieName;
var responseCookies = HttpContext.Current.Response.Cookies;
var requestCookies = HttpContext.Current.Request.Cookies;
var aspxAuthCookieInResponse = responseCookies.AllKeys.Contains(authCookieKey) ? responseCookies[authCookieKey] : null;
var aspxAuthCookieInRequest = requestCookies.AllKeys.Contains(authCookieKey) ? requestCookies[authCookieKey] : null;
// Take ASPXAUTH cookie from either response or request.
var cookie = aspxAuthCookieInResponse ?? aspxAuthCookieInRequest;
var authTicket = FormsAuthentication.Decrypt(cookie.Value); // Todo: Check for nulls.
// Using the name!
var userName = authTicket.Name;
There are no custom fields for forms authentication. You'll just have to use session. That's what it's there for you know. ;) Just don't forget - forms authentication cookie and session are two independant things. They even each have their own timeouts. So the session won't be reset when a user logs out unless you do so yourself.
What about using Profiles to store the extra info with the User?
The simplest option is to use the session. By default session state is stored in memory and will be lost when the ASP.NET worker process recycles, however you can configure it to use state service instead, which retains session info in a separate process:
http://msdn.microsoft.com/en-us/library/ms178586.aspx
Another option would be to use profiles. As it sounds like you already have 'profile' information stored in your own tables, you'd probably have to write a custom provider for it so it's a more complex solution.

Categories