Now we'll start adding some of the functionality to the application. Membase does not have a schema, so we can feel free to add whatever we need when we're writing code. The only stipulation is that if you store a key, you need to be able to recreate that key in the future otherwise you will lose track of the data that you stored in that key.
Add the following instance variables to the top of HomeController.cs:
private static readonly Guid AppSecret = Guid.Parse("A9468ADE-8830-4955-B378-573BBCCC62EF"); private const int SessionTimeoutMinutes = 60;
Then add the methods in Listing 6 below the
Index() method.
Listing 6: Create actions.
/// <summary> /// GET: /Home/Create /// </summary> /// <returns></returns> public ActionResult Create() { return View(); } /// <summary> /// POST: /Home/Create /// </summary> /// <param name="collection"></param> /// <returns></returns> [HttpPost] public ActionResult Create(FormCollection collection) { var client = MvcApplication.MembaseClient; var userName = collection["UserName"]; var password = collection["Password"]; var fullName = collection["FullName"]; // We're going to create a new user in the database // and then return a cookie that will identify the // user for a limited time. var sessionToken = Guid.NewGuid(); var cookie = new HttpCookie("MEMBASE_SESSION", sessionToken.ToString()); ControllerContext.HttpContext.Response.Cookies.Add(cookie); var user = new User { UserId = Guid.NewGuid(), FullName = fullName, Password = EncodePassword(password), UserName = userName }; // Design a key that the user will be able to retrieve again, if and only if // they remember what their password is. This is likely not the only way to // do something like this. String userKey = string.Format("User-{0}-{1}{2}", userName, AppSecret, user.Password); // Store the userKey so that it will expire // after SessionTimeoutMinutes minutes, // forcing the user to log back in if the user hasn't performed // any operations in that time. The key is obfuscated by an application // secret GUID. This is not really secure, just for demonstration purposes. // It is merely relatively unguessable. client.Store(StoreMode.Set, sessionToken.ToString() + AppSecret, userKey, TimeSpan.FromMinutes(SessionTimeoutMinutes)); client.Store(StoreMode.Set, userKey, user.UserId); client.Store(StoreMode.Set, user.UserId.ToString(), user); return RedirectToAction("Index"); } /// <summary> /// Encode a password into a string of hexadecimal /// bytes by hashing it with SHA1 and converting it. /// </summary> /// <param name="password"></param> /// <returns></returns> private static string EncodePassword(string password) { var hashBytes = new SHA1Managed() .ComputeHash(Encoding.ASCII.GetBytes(password)); return BitConverter.ToString(hashBytes); }
The AppSecret constant will be used to
obfuscate the the keys in the database somewhat. Of course, this
is just to provide some perceived security. If your application
does not advertise any of the keys, there would be no need for
this. You will see it is used as part of the key later on in the
code.
In order to create a user, an instance of the User model class is
created and filled in with the data coming from the form. A key is
created directly from the username and password. This way, only
the correct password will lead to being able to load the User
record back into the program. Here the Store()
method is used to add a few records to the database. The user key,
points to the userId, and the userId can be
used to load the User record. Remember, with no schema comes great
flexibility. There are probably a dozen different ways to
accomplish the same thing. Feel free to experiment with your own
ideas.
Here, the actual user's password is never stored, only the SHA1 hashed version of the password is stored.
Now you must add the entry form. Right click on the Views/Home folder and choose Add | View. Name this view Create, and add the contents in Listing 7.
Listing 7: Create.cshtml
@{ ViewBag.Title = "Create"; } <h2>Create</h2> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>User</legend> <p> UserName: <input type="text" name="UserName" /> </p> <p> Password: <input type="password" name="Password" /> </p> <p> Full Name: <input type="text" name="FullName" /> </p> <p> <input type="submit" value="Create" /> </p> </fieldset> } <div> @Html.ActionLink("Go back...", "Index") </div>
We now have everything in place to create a new user account and in stage 4 you will create a login action and views to tie this functionality together.