Hi,
my problem is maybe not related only to MVC, but currently i am developing a web application for multiple tenants (multitenant app). On the log in page i have some log in fields, basically Token, email and password. On the log in event i am going to authenticate
the user. The token is used to find the tenant and the connection string for this tenant (separate DB). The other data, email and password are then connected to the server Db and used to authenticate the user. This is working fine. This data i am storing in
a session to pass it around the pages.
The problem is the "Remember me" option on the log in page. If this is checked, the user should not log in again when he returns to the page at a later time. But if he returns, the session is null, and i lost all the data he entered at the first time log
in. Here is my code.
DataModels.Tenant tenant = BLTenant.GetValidateTenant(token); if (tenant != null) { DataModels.User user = BLUser.GetValidateUser(tenant.TenantToken, email, password, tenant.TenantConnectionString); if (user != null) { FormsAuthentication.SetAuthCookie(user.UserEmail, rememberMe.HasValue ? rememberMe.Value : false); Session[ConstantsUtil.SessionUser] = user; return RedirectToAction("Index", "Home"); } else { ModelState.AddModelError("Login", "Log in failed"); return View("Login"); } } else { ModelState.AddModelError("Login", "Log in failed"); return View("Login"); }
I am looking for a better way to store the users data, especially email, pass and connection string, so that i can use it at a later point when the user returns to the site.
The common solution for this "remember me" scenario is using a Cookie, not a session. But if you need to put the connection string there, just put the identifier in the cookie. So later on you can use the identifier to get the real database name that make
a complete connectionstring in your codes. This is the safer solution for the conditional conn string, in my opinion.
Hmm…
The "remember me" is a cookie, not a session. But the connection string for the DB, including username/pass for the db server, is stored in the session. Storing it to the cookie is not safe, in my opinion. Therefore i am using session. BUT the session is
lost when somebody closes the browser, but comes back in 5 minutes… The user is authenticated, but when i need to display some data a i need the connection string, which is not present…How to solve this?
Hi there. I hope you already have the solution. But, in case you haven’t, i try to make myself clear, using some codes below.
public class HomeController : Controller { public Dictionary<string, string> dbMap = new Dictionary<string,string>(); public HomeController() { dbMap.Add("marvel", "MarvelDB"); //The real database name is MarvelDB dbMap.Add("avenger", "AvengersDB"); //The real database name is AvengersDB } public ActionResult Index() { ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application."; if (Request.Cookies.Count == 0) { var userCookie = new HttpCookie("dbid", "avenger"); userCookie.Expires.AddDays(365); HttpContext.Response.Cookies.Add(userCookie); } string dbName = dbMap[Request.Cookies["dbid"].Value]; SqlConnectionStringBuilder myBuilder = new SqlConnectionStringBuilder(); using (SqlConnection myConnection = new SqlConnection()) { myBuilder.UserID = User.Identity.Name; myBuilder.Password = (string)(Session["password"] == null? "" : Session["password"]); myBuilder.InitialCatalog = dbName; myBuilder.DataSource = "YourServerName"; myBuilder.ConnectTimeout = 30; myConnection.ConnectionString = myBuilder.ConnectionString; //myConnection.Open(); /* SOME QUERY */ //myConnection.Close(); } return View(); } public ActionResult About() { ViewBag.Message = "Your app description page."; return View(); } public ActionResult Contact() { ViewBag.Message = "Your contact page."; return View(); } }
The "dbMap" is the map for the identifier kept in the cookies, so you can get the real db name without expose it to your client.
But this approach still maybe won’t satisfy you, regarding to your own definition of "safe". But in your case, i will definitely go this way. Unless, you change the design of your application so you won’t bother to keep the connection string any more.
Hi,
thanks for the code example. I think its good, but one more doubt: What about a new customer? In this case i would need to add the "new customer DB" in the Home controller like here:
public HomeController() { dbMap.Add("marvel", "MarvelDB"); //The real database name is MarvelDB dbMap.Add("avenger", "AvengersDB"); //The real database name is AvengersDB dbMap.Add("newCustomer1", "CustomDB1"); //The real database name is CustomDB1 dbMap.Add("newCustomer2", "CustomDB2"); //The real database name is CustomDB2 }
That means i would need to build the whole project again and deploy the ddl’s, right?
Hi again,
This is, of course, just a rough example of using a map. So, it is hard coded this way. You could store this map data somewhere to be retrieved back here, so you don’t need to recompile anything when it’s happen. You could think of some kind of a "new registration
system", i suppose.