Tuesday, February 5, 2013

Mvc4 fresh site 'simplemembershipprovider' with existing user login table(s)

So there are a few requirements to using WebMatrix.WebData.SimpleMembershipProvider. One of these is that your PasswordHash must be stored in a column called Password. Argh! I've gotten the login part and only the login part working. Here's my Context:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Globalization;
using System.Web.Security;

namespace Models
{
  public class UsersContext : DbContext
  {
    public UsersContext()
      : base("DefaultConnection")
    {
      this.Configuration.LazyLoadingEnabled = false; //me no likey.
      Database.SetInitializer<UsersContext>(null); //clear out all the strategies so that EF will leave the existing db ALONE.

    }

    public DbSet<User> Users { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
      //throw new UnintentionalCodeFirstException(); in the event you don't want code-first
    }
  }

  [Table("User")]
  public class User
  {
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    [Column("User_Id")]
    public int UserId { get; set; }

    [Column("User_Name")]
    public string UserName { get; set; }

    [Column("Password_Hash")]
    public string PasswordHash { get; set; }
  }
}
No changes made in Global.asax added to configuration system.web :
    <membership defaultProvider="SimpleMembershipProvider">
      <providers>
        <clear/>
        <add name="SimpleMembershipProvider" type="PaySpan.Jms.Models.SimpleMembershipProvider,PaySpan.Jms"/>
      </providers>
    </membership>
Here is the derived SimpleMembershipProvider:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Web;
using System.Web.Helpers;
using System.Web.WebPages;

using Payformance.Core.Cryptography;

namespace PaySpan.Jms.Models
{
  public class SimpleMembershipProvider : WebMatrix.WebData.SimpleMembershipProvider
  {
    
    
    // Inherited from MembershipProvider ==> Forwarded to previous provider if this provider hasn't been initialized
    public override bool ValidateUser(string username, string password)
    {
      var userHash = Crypto.HashPassword(password); //if only we were using the default asp hash provider =(
      var ourHash = Hash.HashToString(password);
      Trace.WriteLine("userHash:" + userHash);
      Trace.WriteLine("ourHash:" + ourHash);
      try
      {
        Trace.WriteLine("trying custom validate user");
        using (var db = new UsersContext())
        {
          Trace.WriteLine("trying to get userId/Hash");
          var u=db.Users.Where(up => up.UserName == username).Select(up => new { up.UserId, up.PasswordHash}).FirstOrDefault();

          Trace.WriteLine("tracing user");
          Trace.WriteLine(u);


          //if (u!=null && Crypto.VerifyHashedPassword(u.PasswordHash,userHash)) return true; // this would be if you want to use the default hash provider
          return u != null && ourHash == u.PasswordHash;

        }
        return base.ValidateUser(username, password);
      }
      catch (Exception ex)
      {
        Trace.WriteLine(ex);
        throw;
      }
    }
  }
}
Then in the provided InitializeSimpleMembershipAttribute changed it to
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "User", "User_Id", "User_Name", autoCreateTables: false);

No comments:

Post a Comment