Subby
Subby

Reputation: 5480

ASP.NET MVC - How does WebSecurity work?

I have an ASP.NET MVC 4 project which I have successfully connected to a MySQL database. I have done this by adding a ADO.NET/EntityFramework class which created a Model.edmx object.

Within the database, I have created a table called user which holds what you should expect in a User table such as Email, UserName, Password, FirstName. etc etc.

I have created some dummy records and added the following code to the Login method within the AccountController:

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        var database = new Database();
        user user = database.SelectByUserName(model.UserName).FirstOrDefault<user>();
        var hash = Utilities.HashPassword(model.Password, user.Salt);

        if (hash == user.Password && WebSecurity.Login(user.UserName, user.Password))
        {
            //Correct Login Details!
            RedirectToAction("About", "Home");
        }
    }

    // If we got this far, something failed, redisplay form
    ModelState.AddModelError("", "The user name or password provided is incorrect.");
    return View(model);
}

For some reason, the WebSecurity.Login method returns false and the user isn't redirected to the Home page.

Why is it returning false? What am I missing and how would the WebSecurity.Login even know what credentials are required i.e. How does it even know that it should look inside the user table which I created?

Upvotes: 2

Views: 5728

Answers (2)

siva.k
siva.k

Reputation: 1344

WebSecurity doesn't default to looking at your database, it will actually make it's own tables using the DefaultConnection that is defined in Web.Config. To work around this you need to add a new connection string Web.Config and then during app initialization force WebSecurity to look at that connection.

The easiest way to accomplish this, assuming you have a MySQL specific connection string in your Web.Config named "AccountConnection" is by adding the following to your Application_Start()

LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);

And then you'll need the following fields and function:

    private static SimpleMembershipInitializer _initializer;
    private static object _initializerLock = new object();
    private static bool _isInitialized;

    private class SimpleMembershipInitializer
    {
        public SimpleMembershipInitializer()
        {
            Database.SetInitializer<UsersContext>(null);

            try
            {
                using (var context = new UsersContext())
                {
                    if (!context.Database.Exists())
                    {
                        // Create the SimpleMembership database without Entity Framework migration schema
                        ((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
                    }
                }
                // Overload is: Web.Config Connection string by name, user table name, user id column name, user name column name, auto create missing tables
                WebSecurity.InitializeDatabaseConnection("AccountConnection", "UserProfile", "UserId", "Email", autoCreateTables: true);
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException("The Membership database could not be initialized.", ex);
            }
        }
    }

Whether you can make WebSecurity work with MySQL I have no idea, though I believe I've read some place that it is supported.

Note: the UserContext should have been auto generated when you installed WebSecurity into your solution. If not it's a CodeFirst model that you can easily add.

Upvotes: 4

Erik Philips
Erik Philips

Reputation: 54628

There are one of two reasons your code will not work. Understand that WebSecurity and SimpleMembershipProvider (assuming you are using it) uses PBKDF2 algorithm to populate the password field when you call WebSecurity.CreateUserAndAccount or WebSecurity.CreateAccount.

So Either:

You did not use one of these two methods to create the user, in which case WebSecurity.Login will almost always fail (99.99%).

or

You did use one of the methods above and the code in Utilities.HashPassword() (which seems redundant since the Create Account methods listed above hash passwords anyway...) does not hash the password Exactly the same way WebSecurity does so hash == user.Password will always fail.

Upvotes: 2

Related Questions