Extending Identity – Account Verification

As stated in the previous blog post Identity is very useful for Asp.net developers out of the box. There is some functionality that must be configured to make it completely functional. User can register and they will be redirected to a default page that asks them to check and confirm their email. The system is not setup however to email the confirmation message nor is it configured to lock users out until they confirm their email. This takes a little configuration but I take it a step further to make it as user friendly as possible. This is the second post in a 3 part series on extending the ASP.NET Identity Framework.

The first thing that I do is to create an email service. I am going to have to send email from multiple places so to keep with the DRY principle I create the email functionality in a separate class/method that I can call from anywhere. To do this I typically create a CommunicationService class inside a new Utilities folder.  In this new class I add the following EmailService:

public class CommunicationServices

{

public object EmailService(string toAddress, string subject, string message )

{

#region PRODUCTION EMAIL

// Create and Configure the Mail Message

MailMessage msg = new MailMessage(

"no-reply@domain.com", // From

toAddress, // To

subject, // Subject

message);

 

msg.IsBodyHtml = true;

 

// Create and Configure the SMTP client

SmtpClient client = new SmtpClient("mail.domain.com");

client.Credentials = new NetworkCredential("no-reply@domain.com", "SecretPassword");

 

using (client)

{

try

{

client.Send(msg);

}

catch (Exception e)

{

return e;

}

 

return "Success";

}

#endregion

}

}

The email setting above will need to be adjusted to what your server requires but essentially I will be able to pass in any email address, subject and message to this service and it will send the message passed to the service to the email address that was also passed.

Next we need to use the communication service to set up the SendAsync method of the EmailService class that is located in the App_Start/IdentityConfig.cs file.

public class EmailService : IIdentityMessageService

{

public Task SendAsync(IdentityMessage message)

{

CommunicationServices comm = new CommunicationServices();

comm.EmailService(message.Body, message.Destination, message.Subject);

 

return Task.FromResult(0);

}

}

The verification email is generated in the Register method of the AccountController. The problem with this is that if there is an issue and the user does not get the verification email there is really no easy way to resend it to them. To solve this problem I used much of the code in the Registration method to create a separate SendEmailConfirmationTokenAsync method that I can call from multiple places to send or resend the verification email. I add the following method to the bottom of the AccountController.

private async Task<string> SendEmailConfirmationTokenAsync(string email, string subject)

{

var currentUser = UserManager.FindByEmail(email);

&nbsp;

string code = await UserManager.GenerateEmailConfirmationTokenAsync(currentUser.Id);

var callbackUrl = Url.Action("ConfirmEmail", "Account",

new { userId = currentUser.Id, code = code }, protocol: Request.Url.Scheme);

&nbsp;

CommunicationServices comm = new CommunicationServices();

comm.EmailService(email, subject,

"Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>");

&nbsp;

return callbackUrl;

}

I then modify the Register and Login links to send the verification email if required. In the HttpPost Register method it is always required to send the verification message since they just registered. To do this I modify the code in the if(result.Succeeded) block to the following.

await SendEmailConfirmationTokenAsync(model.Email, "Please Confirm you Email for domain.com");

return View("EmailNotConfirmed");

In the HttpPost Login method does not check for email confirmation by default even through it is a default field that Identity creates in the AspNetUsers table. If a user tries to login and they have not confirmed their email address I want to do two things. First I want to resend the verification email to them in case they did not receive it when they registered. Second I want to redirect them to a page instructing them to check their email and verify their address. Resending the verification email may not be required so I add the following if() block check for confirmation and then proceed from there. To do this I simply add the following code into the if(user != null) block. I typically enter this after my check for if(user.IsBlocked) since I don’t want to process any more code than necessary if a user is blocked.

if (!UserManager.IsEmailConfirmed(user.Id))

{

await SendEmailConfirmationTokenAsync(model.Email, "Please Confirm you Email for domain.com");

return View("EmailNotConfirmed", model);

}

From here you should have an application that will send the verification email for your website, allow users to verify their account and prevent any user from logging in if they have not confirmed their account as well as sending the verification email again in case they did not receive it.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s