ASP.NET MVC 2 Custom Membership Provider Tutorial
Trang 1 trong tổng số 1 trang
ASP.NET MVC 2 Custom Membership Provider Tutorial
In this tutorial I will show how to implement Custom Membership Provider in ASP.NET MVC 2 Web Application using Microsoft Visual Web Developer 2010 Express.
The tutorial will consist of few parts (not sure how many at this stage) and I will try to cover custom implementations of membership, role and profile providers.
I will use custom database schema and Entity Framework with additional repository class sitting between the Membership Provider and Entity Framework model.
Let’s start by creating a new Project called CustomMembership.
[You must be registered and logged in to see this image.]
Because we’re using ASP.NET MVC 2 Web Application template, we can instantly run the application and get:
[You must be registered and logged in to see this image.]
This default project is already configured to use ASPNETDB database (or to create one if does not exist) located in App_Data folder and standard ASP.NET Membership Provider . We want to use custom database schema to store membership information and to do that we will have to implement Custom Membership Provider. So let’s do it!
First, create new class called MyMembershipProvider in Models folder.
[You must be registered and logged in to see this image.]
Remove the namespace definition and make your class inherit MembershipProvider class from System.Web.Security namespace.
Move MyMembershipProvider.cs file to App_Data folder by right clicking App_Data folder and adding an existing item, and remove it from Models folder by right clicking MyMembershipProvider.cs file and excluding it from the project.
[You must be registered and logged in to see this image.]
Open App_Data\MyMembershipProvider.cs file for editing and right click on MembershipProvider class name and from the context menu choose Implement Abstract Class.
[You must be registered and logged in to see this image.]
This will create override methods for MembershipProvider class.
[You must be registered and logged in to see this image.]
You have just created Custom Membership Provider. None of the functionality is implemented yet but let’s just carry on and configure our application to use it.
Open Web.Config file in root of your project and change setting in membership node to use your new provider.
If we run our project now, and try to log in using the link on the page you will see the following errors:
[You must be registered and logged in to see this image.]
which is correct as we have not implemented any of the methods yet.
Let’s try to modify the ValidateUser method to return true and let us in.
Now we should be able to log ourselves in as long as username and password are the same.
Let’s give it a go.
[You must be registered and logged in to see this image.]
This is it for now! In the next part we will implement the database backend and UserRepository class.
The tutorial will consist of few parts (not sure how many at this stage) and I will try to cover custom implementations of membership, role and profile providers.
I will use custom database schema and Entity Framework with additional repository class sitting between the Membership Provider and Entity Framework model.
Let’s start by creating a new Project called CustomMembership.
[You must be registered and logged in to see this image.]
Because we’re using ASP.NET MVC 2 Web Application template, we can instantly run the application and get:
[You must be registered and logged in to see this image.]
This default project is already configured to use ASPNETDB database (or to create one if does not exist) located in App_Data folder and standard ASP.NET Membership Provider . We want to use custom database schema to store membership information and to do that we will have to implement Custom Membership Provider. So let’s do it!
First, create new class called MyMembershipProvider in Models folder.
[You must be registered and logged in to see this image.]
Remove the namespace definition and make your class inherit MembershipProvider class from System.Web.Security namespace.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
public class MyMembershipProvider : MembershipProvider
{
}
Move MyMembershipProvider.cs file to App_Data folder by right clicking App_Data folder and adding an existing item, and remove it from Models folder by right clicking MyMembershipProvider.cs file and excluding it from the project.
[You must be registered and logged in to see this image.]
Open App_Data\MyMembershipProvider.cs file for editing and right click on MembershipProvider class name and from the context menu choose Implement Abstract Class.
[You must be registered and logged in to see this image.]
This will create override methods for MembershipProvider class.
[You must be registered and logged in to see this image.]
You have just created Custom Membership Provider. None of the functionality is implemented yet but let’s just carry on and configure our application to use it.
Open Web.Config file in root of your project and change setting in membership node to use your new provider.
<membership defaultProvider="CustomMembershipProvider">
<providers>
<clear/>
<add name="CustomMembershipProvider" type="MyMembershipProvider"
connectionStringName="ApplicationServices"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="false"
requiresUniqueEmail="false"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="6"
minRequiredNonalphanumericCharacters="0"
passwordAttemptWindow="10"
applicationName="/" />
</providers>
</membership>
If we run our project now, and try to log in using the link on the page you will see the following errors:
[You must be registered and logged in to see this image.]
which is correct as we have not implemented any of the methods yet.
Let’s try to modify the ValidateUser method to return true and let us in.
public override bool ValidateUser(string username, string password)
{
if (username == password)
{
return true;
}
else
{
return false;
}
}
Now we should be able to log ourselves in as long as username and password are the same.
Let’s give it a go.
[You must be registered and logged in to see this image.]
This is it for now! In the next part we will implement the database backend and UserRepository class.
ASP.NET MVC 2 Custom Membership Provider Tutorial – Part 2
Just to quickly wrap up what we’ve done so far:
We created new project using ASP.NET MVC 2 Web Application to make use of the layout (login pages, master page, login controls) and speed up our development.
We created Custom Membership Provider and we implemented custom logic into the ValidateUser method to show how we can override Membership Provider’s methods.
In this part of the tutorial we’re going to implement a database, create UserRepository class which will contain data logic (to keep the provider as simple as possible and to leave Entity Framework model untouched so we can make modifications to the database without breaking things), and implement some of the Membership Provider’s basic methods.
First of all, I would like to say that this is first time I’m doing this too. Although I’m few steps ahead of the tutorial I’m open to suggestions on how the implementation can be improved (both, coding and the way it works).
While I’m at it, I’ll just quickly (sorry for all the delay) mention where I see this tutorial going in the next few parts.
We’re going to implement all default Membership Provider methods to make it tidy. Even if it means just returning hard-coded value like password format (for example: we don’t need the option between text/hashed passwords).
We will also implement email validation system that will request clicking auto-generated link in an email to register, reset password and change email address.
After we’ve done that, we will implement Role Provider and we will create admin section of the application.
So, coming back to this part of the tutorial, first we will need a database table to store all membership information. The table I’m proposing is basically a hybrid of aspnet_membership table from ASPNETDB database and Users table from Tank_Auth authentication library for CodeIgniter PHP framework (Check out the following link on Stack Overflow to find out more about Tank_Auth, it’s very informative – What Code Igniter authentication library is best? – Stack Overflow).
Let’s start by adding the database to our project. Right click App_Data folder, Add -> New Item…, Select SQL Server Database, call it CustomMembership.mdf and click Add.
[You must be registered and logged in to see this image.]
In Database Explorer, right click on the Tables node and Add New Table. Create the following table:
[You must be registered and logged in to see this image.]
Make UserId column a Primary Key and an Identity Column and save the table with the name Users.
[You must be registered and logged in to see this image.]
Back in the Solution Explorer, right click Models folder Add -> New Item…, Select ADO.NET Entity Data Model, call it CustomMembership.edmx and click Add.
[You must be registered and logged in to see this image.]
Select Generate from Database and click Next.
Change the connection name to CustomMembershipDB and click Next.
[You must be registered and logged in to see this image.]
Select Tables, change Model Namespace to CustomMembership.Models and Finish the wizard.
[You must be registered and logged in to see this image.]
Back in Solution Explorer open Web.config file and delete default ASPNETDB connection. We had to keep it there because Membership Provider needs connectionStringName parameter. Now, we have our DB connection which by the way Membership Provider is not going to use directly anyway, we can delete the ASPNETDB connection.
Change connectionStringName parameter value in Membership, Role and Profile provider nodes in Web.config file like on the screenshot below.
[You must be registered and logged in to see this image.]
We can quickly run our application to confirm that we didn’t break anything… yet.
While we have the application running see what happens if we click Register link on the login page.
[You must be registered and logged in to see this image.]
We created new project using ASP.NET MVC 2 Web Application to make use of the layout (login pages, master page, login controls) and speed up our development.
We created Custom Membership Provider and we implemented custom logic into the ValidateUser method to show how we can override Membership Provider’s methods.
In this part of the tutorial we’re going to implement a database, create UserRepository class which will contain data logic (to keep the provider as simple as possible and to leave Entity Framework model untouched so we can make modifications to the database without breaking things), and implement some of the Membership Provider’s basic methods.
First of all, I would like to say that this is first time I’m doing this too. Although I’m few steps ahead of the tutorial I’m open to suggestions on how the implementation can be improved (both, coding and the way it works).
While I’m at it, I’ll just quickly (sorry for all the delay) mention where I see this tutorial going in the next few parts.
We’re going to implement all default Membership Provider methods to make it tidy. Even if it means just returning hard-coded value like password format (for example: we don’t need the option between text/hashed passwords).
We will also implement email validation system that will request clicking auto-generated link in an email to register, reset password and change email address.
After we’ve done that, we will implement Role Provider and we will create admin section of the application.
So, coming back to this part of the tutorial, first we will need a database table to store all membership information. The table I’m proposing is basically a hybrid of aspnet_membership table from ASPNETDB database and Users table from Tank_Auth authentication library for CodeIgniter PHP framework (Check out the following link on Stack Overflow to find out more about Tank_Auth, it’s very informative – What Code Igniter authentication library is best? – Stack Overflow).
Let’s start by adding the database to our project. Right click App_Data folder, Add -> New Item…, Select SQL Server Database, call it CustomMembership.mdf and click Add.
[You must be registered and logged in to see this image.]
In Database Explorer, right click on the Tables node and Add New Table. Create the following table:
[You must be registered and logged in to see this image.]
Make UserId column a Primary Key and an Identity Column and save the table with the name Users.
[You must be registered and logged in to see this image.]
Back in the Solution Explorer, right click Models folder Add -> New Item…, Select ADO.NET Entity Data Model, call it CustomMembership.edmx and click Add.
[You must be registered and logged in to see this image.]
Select Generate from Database and click Next.
Change the connection name to CustomMembershipDB and click Next.
[You must be registered and logged in to see this image.]
Select Tables, change Model Namespace to CustomMembership.Models and Finish the wizard.
[You must be registered and logged in to see this image.]
Back in Solution Explorer open Web.config file and delete default ASPNETDB connection. We had to keep it there because Membership Provider needs connectionStringName parameter. Now, we have our DB connection which by the way Membership Provider is not going to use directly anyway, we can delete the ASPNETDB connection.
Change connectionStringName parameter value in Membership, Role and Profile provider nodes in Web.config file like on the screenshot below.
[You must be registered and logged in to see this image.]
We can quickly run our application to confirm that we didn’t break anything… yet.
While we have the application running see what happens if we click Register link on the login page.
[You must be registered and logged in to see this image.]
ASP.NET MVC 2 Custom Membership Provider Tutorial – Part 2 - continue
We could just hard-code MinRequiredPasswordLength propery into Custom Membership Provider if we wanted to.
What happens is that when the Membership Provider is initialized, the Initialize() method is called. It reads Web.config file and sets Membership Provider object’s properties. So, lets implement Initialize method in MyMembershipProvider class
First, lets add a reference to System.Collections.Specialized assembly:
Next, create helper function which we will use to read config values.
Next, lets add properties from Web.config file. W
e’re going to hard code some of the provider’s default properties. We will want unique email and hashed password and we don’t want to let users to retrieve their passwords (not even, using QuestionAndAnswer)
And finally, lets add Initialize method.
What happens is that when the Membership Provider is initialized, the Initialize() method is called. It reads Web.config file and sets Membership Provider object’s properties. So, lets implement Initialize method in MyMembershipProvider class
First, lets add a reference to System.Collections.Specialized assembly:
using System.Collections.Specialized;
Next, create helper function which we will use to read config values.
//
// A helper function to retrieve config values from the configuration file.
//
private string GetConfigValue(string configValue, string defaultValue)
{
if (string.IsNullOrEmpty(configValue))
return defaultValue;
return configValue;
}
Next, lets add properties from Web.config file. W
e’re going to hard code some of the provider’s default properties. We will want unique email and hashed password and we don’t want to let users to retrieve their passwords (not even, using QuestionAndAnswer)
//
// Properties from web.config, default all to False
//
private string _ApplicationName;
private bool _EnablePasswordReset;
private bool _EnablePasswordRetrieval = false;
private bool _RequiresQuestionAndAnswer = false;
private bool _RequiresUniqueEmail = true;
private int _MaxInvalidPasswordAttempts;
private int _PasswordAttemptWindow;
private int _MinRequiredPasswordLength;
private int _MinRequiredNonalphanumericCharacters;
private string _PasswordStrengthRegularExpression;
private MembershipPasswordFormat _PasswordFormat = MembershipPasswordFormat.Hashed;
And finally, lets add Initialize method.
public override void Initialize(string name, NameValueCollection config)
{
if (config == null)
throw new ArgumentNullException("config");
if (name == null || name.Length == 0)
name = "CustomMembershipProvider";
if (String.IsNullOrEmpty(config["description"]))
{
config.Remove("description");
config.Add("description", "Custom Membership Provider");
}
base.Initialize(name, config);
_ApplicationName = GetConfigValue(config["applicationName"],
System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath);
_MaxInvalidPasswordAttempts = Convert.ToInt32(
GetConfigValue(config["maxInvalidPasswordAttempts"], "5"));
_PasswordAttemptWindow = Convert.ToInt32(
GetConfigValue(config["passwordAttemptWindow"], "10"));
_MinRequiredNonalphanumericCharacters = Convert.ToInt32(
GetConfigValue(config["minRequiredNonalphanumericCharacters"], "1"));
_MinRequiredPasswordLength = Convert.ToInt32(
GetConfigValue(config["minRequiredPasswordLength"], "6"));
_EnablePasswordReset = Convert.ToBoolean(
GetConfigValue(config["enablePasswordReset"], "true"));
_PasswordStrengthRegularExpression = Convert.ToString(
GetConfigValue(config["passwordStrengthRegularExpression"], ""));
}
Re: ASP.NET MVC 2 Custom Membership Provider Tutorial
I think the function is pretty much self explanatory. If you remove all unnecessary line breaks it will look much tidier.
We can edit Web.config‘s membership node and delete all the hardcoded parameters.
Next, let’s implement the properties fully into our Custom Membership Provider.
Open MyMembershipProvider file and starting from the top edit properties and methods as below:
We can edit Web.config‘s membership node and delete all the hardcoded parameters.
<membership defaultProvider="CustomMembershipProvider">
<providers>
<clear />
<add name="CustomMembershipProvider"
type="MyMembershipProvider"
connectionStringName="CustomMembershipDB"
enablePasswordReset="true"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="6"
minRequiredNonalphanumericCharacters="0"
passwordAttemptWindow="10"
applicationName="/" />
</providers>
</membership>
Next, let’s implement the properties fully into our Custom Membership Provider.
Open MyMembershipProvider file and starting from the top edit properties and methods as below:
public override string ApplicationName
{
get { return _ApplicationName; }
set { _ApplicationName = value; }
}
Re: ASP.NET MVC 2 Custom Membership Provider Tutorial
Because we will not implement password reset using security question and answer we can change:
At this point, we can run the application and go to Log In -> Register page and we will see:
[You must be registered and logged in to see this image.]
with minimum password length being taken from Web.config file.
In case I’ve made some typos while copy and pasting the code here you can download MyMembershipProvider.cs file up to this point of the tutorial:
[You must be registered and logged in to see this link.]
If we try to register new account we will get an error about CreateUser method not being implemented.
Before we implement CreateUser method we need to implement 2 other methods which are used by CreateUser method: GetUser and GetUsernameByEmail.
We need them both to check for existing usernames and email addresses in our database.
Let’s start by creating UserRepository class.
Right click Models folder, Add -> Class…, call it UserRepository and click Add.
public override bool ChangePasswordQuestionAndAnswer(string username,
string password,
string newPasswordQuestion,
string newPasswordAnswer)
{
return false;
}
public override bool EnablePasswordReset
{
get { return _EnablePasswordReset; }
}
public override bool EnablePasswordRetrieval
{
get { return _EnablePasswordRetrieval; }
}
public override int MaxInvalidPasswordAttempts
{
get { return _MaxInvalidPasswordAttempts; }
}
public override int MinRequiredNonAlphanumericCharacters
{
get { return _MinRequiredNonalphanumericCharacters; }
}
public override int MinRequiredPasswordLength
{
get { return _MinRequiredPasswordLength; }
}
public override int PasswordAttemptWindow
{
get { return _PasswordAttemptWindow; }
}
public override MembershipPasswordFormat PasswordFormat
{
get { return _PasswordFormat; }
}
public override string PasswordStrengthRegularExpression
{
get { return _PasswordStrengthRegularExpression; }
}
public override bool RequiresQuestionAndAnswer
{
get { return _RequiresQuestionAndAnswer; }
}
public override bool RequiresUniqueEmail
{
get { return _RequiresUniqueEmail; }
}
At this point, we can run the application and go to Log In -> Register page and we will see:
[You must be registered and logged in to see this image.]
with minimum password length being taken from Web.config file.
In case I’ve made some typos while copy and pasting the code here you can download MyMembershipProvider.cs file up to this point of the tutorial:
[You must be registered and logged in to see this link.]
If we try to register new account we will get an error about CreateUser method not being implemented.
Before we implement CreateUser method we need to implement 2 other methods which are used by CreateUser method: GetUser and GetUsernameByEmail.
We need them both to check for existing usernames and email addresses in our database.
Let’s start by creating UserRepository class.
Right click Models folder, Add -> Class…, call it UserRepository and click Add.
Re: ASP.NET MVC 2 Custom Membership Provider Tutorial
[You must be registered and logged in to see this image.]
In UserRepository class, add reference to System.Web.Security assembly:
We’re going to implement 3 methods at this stage:
CreateUser:
In UserRepository class, add reference to System.Web.Security assembly:
using System.Web.Security;
We’re going to implement 3 methods at this stage:
CreateUser:
public MembershipUser CreateUser(string username, string password, string email)
{
using (CustomMembershipDB db = new CustomMembershipDB())
{
User user = new User();
user.UserName = username;
user.Email = email;
user.Password = password;
user.PasswordSalt = "1234";
user.CreatedDate = DateTime.Now;
user.IsActivated = false;
user.IsLockedOut = false;
user.LastLockedOutDate = DateTime.Now;
user.LastLoginDate = DateTime.Now;
db.AddToUsers(user);
db.SaveChanges();
return GetUser(username);
}
}
Re: ASP.NET MVC 2 Custom Membership Provider Tutorial
We can see that our UserRepository CreateUser method uses Entity Data Model (CustomMembershipDB) we created earlier. We will come back to hasing and salting the password in the next part of the tutorial.
It creates User object, saves it to DB and returns user object of MembershipUser type.
In case you’re wondering why we assign DateTime.Now values to LastLockedOutDate and LastLoginDate. This is because in default MembershipUser type these properties are not Nullable, which means that they can’t store NULL values. There is a way to implement DateTime? nullable type but for the simplicity we’ll just populate the fields with current time on user creation.
GetUserNameByEmail:
GetUser:
It creates User object, saves it to DB and returns user object of MembershipUser type.
In case you’re wondering why we assign DateTime.Now values to LastLockedOutDate and LastLoginDate. This is because in default MembershipUser type these properties are not Nullable, which means that they can’t store NULL values. There is a way to implement DateTime? nullable type but for the simplicity we’ll just populate the fields with current time on user creation.
GetUserNameByEmail:
public string GetUserNameByEmail(string email)
{
using (CustomMembershipDB db = new CustomMembershipDB())
{
var result = from u in db.Users where (u.Email == email) select u;
if (result.Count() != 0)
{
var dbuser = result.FirstOrDefault();
return dbuser.UserName;
}
else
{
return "";
}
}
}
GetUser:
public MembershipUser GetUser(string username)
{
using (CustomMembershipDB db = new CustomMembershipDB())
{
var result = from u in db.Users where (u.UserName == username) select u;
if (result.Count() != 0)
{
var dbuser = result.FirstOrDefault();
string _username = dbuser.UserName;
int _providerUserKey = dbuser.UserId;
string _email = dbuser.Email;
string _passwordQuestion = "";
string _comment = dbuser.Comments;
bool _isApproved = dbuser.IsActivated;
bool _isLockedOut = dbuser.IsLockedOut;
DateTime _creationDate = dbuser.CreatedDate;
DateTime _lastLoginDate = dbuser.LastLoginDate;
DateTime _lastActivityDate = DateTime.Now;
DateTime _lastPasswordChangedDate = DateTime.Now;
DateTime _lastLockedOutDate = dbuser.LastLockedOutDate;
MembershipUser user = new MembershipUser("CustomMembershipProvider",
_username,
_providerUserKey,
_email,
_passwordQuestion,
_comment,
_isApproved,
_isLockedOut,
_creationDate,
_lastLoginDate,
_lastActivityDate,
_lastPasswordChangedDate,
_lastLockedOutDate);
return user;
}
else
{
return null;
}
}
}
Re: ASP.NET MVC 2 Custom Membership Provider Tutorial
Again, we can see that some of the properties get DateTime.Now value, and again this is because MembershipUser constructor needs the values and can’t accept NULLs.
So basically what the method does is; It connects to database and reads the user data; It then generates new MembershipUser object with properties from database and finally it returns the object.
UserRepository class can be downloaded here:
[You must be registered and logged in to see this link.]
Now, let’s go back to MyMembershipProvider.cs, add the reference to CustomMembership.Models namespace
and implement the following methods:
GetUserNameByEmail:
GetUser(string username, bool userIsOnline) - (not the one with userProviderKey argument):
and finally CreateUser itself:
So basically what the method does is; It connects to database and reads the user data; It then generates new MembershipUser object with properties from database and finally it returns the object.
UserRepository class can be downloaded here:
[You must be registered and logged in to see this link.]
Now, let’s go back to MyMembershipProvider.cs, add the reference to CustomMembership.Models namespace
using CustomMembership.Models;
and implement the following methods:
GetUserNameByEmail:
public override string GetUserNameByEmail(string email)
{
UserRepository _user = new UserRepository();
return _user.GetUserNameByEmail(email);
}
GetUser(string username, bool userIsOnline) - (not the one with userProviderKey argument):
public override MembershipUser GetUser(string username, bool userIsOnline)
{
UserRepository _user = new UserRepository();
return _user.GetUser(username);
}
and finally CreateUser itself:
public override MembershipUser CreateUser(string username,
string password,
string email,
string passwordQuestion,
string passwordAnswer,
bool isApproved,
object providerUserKey,
out MembershipCreateStatus status)
{
ValidatePasswordEventArgs args = new ValidatePasswordEventArgs(username,
password,
true);
OnValidatingPassword(args);
if (args.Cancel)
{
status = MembershipCreateStatus.InvalidPassword;
return null;
}
if (RequiresUniqueEmail && GetUserNameByEmail(email) != "")
{
status = MembershipCreateStatus.DuplicateEmail;
return null;
}
MembershipUser u = GetUser(username, false);
if (u == null)
{
UserRepository _user = new UserRepository();
_user.CreateUser(username, password, email);
status = MembershipCreateStatus.Success;
return GetUser(username, false);
}
else
{
status = MembershipCreateStatus.DuplicateUserName;
}
return null;
}
Re: ASP.NET MVC 2 Custom Membership Provider Tutorial
MyMembershipProvider class up to this point in the tutorial can be downloaded here:
[You must be registered and logged in to see this link.]
At this point, we should be able to register using the registration form of our application (Log In -> Regsiter – or /Account/Register link) and check directly in the database if the account has been created.
It would also be easy enough to modify ValidateUser method to validate against the database but because there is still few things we need to do during user creation process (hash the passwords and generate salt for example) we will leave it for the next part of the tutorial.
[You must be registered and logged in to see this link.]
At this point, we should be able to register using the registration form of our application (Log In -> Regsiter – or /Account/Register link) and check directly in the database if the account has been created.
It would also be easy enough to modify ValidateUser method to validate against the database but because there is still few things we need to do during user creation process (hash the passwords and generate salt for example) we will leave it for the next part of the tutorial.
Re: ASP.NET MVC 2 Custom Membership Provider Tutorial
In the previous part of the tutorial we implemented CreateUser method which successfully creates new user in the database.
First thing we want to do now is to generate password salt.
Open UserRepository.cs, and add a reference to System.Security.Cryptography:
using System.Security.Cryptography;
and function to generate the salt (within UserRepository class):
Finally,change the CreateUser method to generate and save the salt to database with other user data.
We can go ahead and try it. Run your application and register new user account. If you check the database you will see random salt generated during the registration.
Now, let’s hash the password. Add the following code to UserRepository class:
and modify CreateUser method again to store hashed password. Because we’re going to use user.passwordSalt property as an argument in CreatePasswordHash method we need to reorder the properties so the salt gets generated before the password is hashed:
I am aware that this is probably not the best method to hash the password and that the hashing and salt generating methods can be improved but this is not the point of this tutorial so I’ll leave it as it is.
The UserRepository.cs file up to this point in the tutorial can be downloaded here:
[You must be registered and logged in to see this link.]
gmail xem tại: [You must be registered and logged in to see this link.]
copyright by [You must be registered and logged in to see this link.]
First thing we want to do now is to generate password salt.
Open UserRepository.cs, and add a reference to System.Security.Cryptography:
using System.Security.Cryptography;
and function to generate the salt (within UserRepository class):
private static string CreateSalt()
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] buff = new byte[32];
rng.GetBytes(buff);
return Convert.ToBase64String(buff);
}
Finally,change the CreateUser method to generate and save the salt to database with other user data.
public MembershipUser CreateUser(string username, string password, string email)
{
using (CustomMembershipDB db = new CustomMembershipDB())
{
User user = new User();
user.UserName = username;
user.Email = email;
user.Password = password;
user.PasswordSalt = CreateSalt();
user.CreatedDate = DateTime.Now;
user.IsActivated = false;
user.IsLockedOut = false;
user.LastLockedOutDate = DateTime.Now;
user.LastLoginDate = DateTime.Now;
db.AddToUsers(user);
db.SaveChanges();
return GetUser(username);
}
}
We can go ahead and try it. Run your application and register new user account. If you check the database you will see random salt generated during the registration.
Now, let’s hash the password. Add the following code to UserRepository class:
private static string CreatePasswordHash(string pwd, string salt)
{
string saltAndPwd = String.Concat(pwd, salt);
string hashedPwd =
FormsAuthentication.HashPasswordForStoringInConfigFile(
saltAndPwd, "sha1");
return hashedPwd;
}
and modify CreateUser method again to store hashed password. Because we’re going to use user.passwordSalt property as an argument in CreatePasswordHash method we need to reorder the properties so the salt gets generated before the password is hashed:
public MembershipUser CreateUser(string username, string password, string email)
{
using (CustomMembershipDB db = new CustomMembershipDB())
{
User user = new User();
user.UserName = username;
user.Email = email;
user.PasswordSalt = CreateSalt();
user.Password = CreatePasswordHash(password, user.PasswordSalt);
user.CreatedDate = DateTime.Now;
user.IsActivated = false;
user.IsLockedOut = false;
user.LastLockedOutDate = DateTime.Now;
user.LastLoginDate = DateTime.Now;
db.AddToUsers(user);
db.SaveChanges();
return GetUser(username);
}
}
I am aware that this is probably not the best method to hash the password and that the hashing and salt generating methods can be improved but this is not the point of this tutorial so I’ll leave it as it is.
The UserRepository.cs file up to this point in the tutorial can be downloaded here:
[You must be registered and logged in to see this link.]
gmail xem tại: [You must be registered and logged in to see this link.]
copyright by [You must be registered and logged in to see this link.]
Re: ASP.NET MVC 2 Custom Membership Provider Tutorial
Database Data
[You must be registered and logged in to see this image.]
[You must be registered and logged in to see this image.]
What does this MD5 Encrypter tool do?
MD5Decrypter.co.uk allows you to calculate a number of hash types from a password.
[You must be registered and logged in to see this link.]
[You must be registered and logged in to see this link.]
Re: ASP.NET MVC 2 Custom Membership Provider Tutorial
[You must be registered and logged in to see this link.]
SHA1 with salt on windows phone 7
I have some some time now reshearchd how to encode a password to SHA1 with a salt.
The is the code i used on my web application part, but it will not work on a phone environment.
Silverlight and Windows Phone 7 do not have an ASCIIEncoding. I suggest you use the UTF8Encoding instead. If you are certain that your passwords are always within the ASCII range then this encoding will work the same as the ASCIIEncoding would of had it been present.
If on the other hand you cannot guarantee that passwords are always within the ASCII range then you would need to make sure both ends hash using the UTF8Encoding to ensure generated hashs are the same.
The is the code i used on my web application part, but it will not work on a phone environment.
public class Password
{
private string _password;
private int _salt;
public Password(string strPassword, int nSalt)
{
_password = strPassword;
_salt = nSalt;
}
public string ComputeSaltedHash()
{
// Create Byte array of password string
ASCIIEncoding encoder = new ASCIIEncoding();
Byte[] _secretBytes = encoder.GetBytes(_password);
// Create a new salt
Byte[] _saltBytes = new Byte[4];
_saltBytes[0] = (byte)(_salt >> 24);
_saltBytes[1] = (byte)(_salt >> 16);
_saltBytes[2] = (byte)(_salt >> 8);
_saltBytes[3] = (byte)(_salt);
// append the two arrays
Byte[] toHash = new Byte[_secretBytes.Length + _saltBytes.Length];
Array.Copy(_secretBytes, 0, toHash, 0, _secretBytes.Length);
Array.Copy(_saltBytes, 0, toHash, _secretBytes.Length, _saltBytes.Length);
SHA1 sha1 = SHA1.Create();
Byte[] computedHash = sha1.ComputeHash(toHash);
return encoder.GetString(computedHash);
}
public static int CreateRandomSalt()
{
Byte[] _saltBytes = new Byte[4];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(_saltBytes);
return ((((int)_saltBytes[0]) << 24) + (((int)_saltBytes[1]) << 16) +
(((int)_saltBytes[2]) << 8) + ((int)_saltBytes[3]));
}
public static string CreateRandomPassword(int PasswordLength)
{
String _allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ23456789!\"#¤%&/()=?$+-_.,;'*";
Byte[] randomBytes = new Byte[PasswordLength];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(randomBytes);
char[] chars = new char[PasswordLength];
int allowedCharCount = _allowedChars.Length;
for (int i = 0; i < PasswordLength; i++)
{
chars[i] = _allowedChars[(int)randomBytes[i] % allowedCharCount];
}
return new string(chars);
}
}
Silverlight and Windows Phone 7 do not have an ASCIIEncoding. I suggest you use the UTF8Encoding instead. If you are certain that your passwords are always within the ASCII range then this encoding will work the same as the ASCIIEncoding would of had it been present.
If on the other hand you cannot guarantee that passwords are always within the ASCII range then you would need to make sure both ends hash using the UTF8Encoding to ensure generated hashs are the same.
Re: ASP.NET MVC 2 Custom Membership Provider Tutorial
There is still a problem with SHA1 sha1 = SHA1.Create(); and return encoder.GetString(computedHash);
@DoomStone: You can create an instance of the SHA1 class using new SHA1() and for a string representation of the hash I'd be inclined to use Convert.ToBase64String on the byte array instead of trying to pretend that the set of bytes in anyway represented some encoding of textual characters in a string.
@DoomStone: You can create an instance of the SHA1 class using new SHA1() and for a string representation of the hash I'd be inclined to use Convert.ToBase64String on the byte array instead of trying to pretend that the set of bytes in anyway represented some encoding of textual characters in a string.
Trang 1 trong tổng số 1 trang
Permissions in this forum:
Bạn không có quyền trả lời bài viết
|
|