May 15, 2011
|
Using the confirmation feature for ASP.NET Web Pages security
|
115270 hit(s)
When I described the most basic way to implement security (membership) for ASP.NET Web Pages/Razor websites, I skipped over a feature that you can add to the registration page — namely, confirmation for registration. You're undoubtedly familiar with how this works. You register on a site, and they say "Go check your email!" You get an email from them that requests that you click a link in order to finish the registration process. You do that, and then — but only then — you are allowed to log in.
This two-step process has a couple of benefits. One is that it helps to make sure that whoever is registering is actually a human and not a bot. In a sense, I suppose, it also helps make sure that people who register really want to register, since they need to go to some extra trouble. It also prevents people from registering multiple identities, since their user name is their (real) email name.
Adding confirmation to the registration process requires this:- In the registration page, you create the member account like normal by calling
WebSecurity.CreateUserAndAccount , but you pass true for the requireConfirmationToken parameter.
The method creates the membership account and also returns a token to you. The token is a value (it might look like LR9888HmlCEkiL3/GdUY5g== ) that uniquely identifies the new membership account. In the database record for the membership account, there's an IsConfirmed field that will be set to false. Because of this, the user cannot log in yet.
- You construct and and send a "thanks for joining" email message. The body includes a link whose query string includes the token.
- The user clicks the link. This goes to a confirmation page in your site.
- In the confirmation page, you extract the token from the request. You then call the
WebSecurity.ConfirmAccount method and pass the token. If all goes well, the IsConfirmed field in the membership database is set to True, and the user can then log on. Let us proceed. However, first ...
Email Settings In order to be able to implement membership confirmation, your site has to support the ability to send email. What this boils down to is that you must have access to an outbound (SMTP) mail server. If you signed up for an account with a hosting provider, it's likely that part of your package deal includes email facilities, or at least that they're available. (Note that you often cannot send email from a hosted account via your "normal" email provider like Comcast or Gmail.) Whatever your hosting scenario, you'll need the following values, which you'll need to get from whoever administers the email service you're using:- SMTP server name. This will probably be
smtp.xxxx.com or something similar. Update 12 July 2011: Check with your hosting provider. In my case, it turns out that the name of the SMTP server for apps running on the hoster's server is just localhost . (It took an annoyingly long time to tease this information out of their support forums, grr.)
- SMTP port number. The most common value is 25, but hosters or other email providers sometimes use alternative ports like 587.
- SSL setting. This determines whether the server requires a security.
- User name and password. If the SMTP server requires authentication, you need to be able to provide the credentials for sending email.
I wish I could be more specific about this, but the details vary depending on your situation. If you can't sort out what you need from this, contact tech support for whoever is hosting your site and ask them.[1]
Adding Confirmation to the Registration Page A registration page that uses confirmation is almost the same as the registration page I illustrated before, but it has code to get the token and send email. The page looks like this when the user has finshed registering:
There are lots of ways to implement this; here's one:
confirmationToken = WebSecurity.CreateUserAndAccount(username,password,null,true); var confirmationUrl = "http://mikepope.com/testmembership/ConfirmAccount?confirmation=" + HttpUtility.UrlEncode(confirmationToken); var confirmationLink = String.Format("<a href=\"{0}\">Click to confirm your registration</a>", confirmationUrl);
// This code should actually go into the _AppStart.cshtml file. WebMail.SmtpServer = "smtp.<mySMTPServer>.com"; WebMail.SmtpPort = 25; WebMail.EnableSsl = false; WebMail.UserName = "<myUserName>"; WebMail.From = "mike@mikepope.com"; WebMail.Password = "<myPassword>";
emailBodyText = "<p>Thank you for signing up with us! " + "Please confirm your registration by clicking the following link:</p>" + "<p>" + confirmationLink + "</p>" + "<p>In case you need it, here's the confirmation code:<strong> " + confirmationToken + "</strong></p>"; WebMail.Send( to: username, subject: "Your example account confirmation", body: emailBodyText, isBodyHtml: true );
message = String.Format( "Thank you for registering. An email has been sent to {0}. " + "Please check your email and use the enclosed link to finish registration.", username); There are a few things here to note. The code creates a hard-coded URL (confirmationUrl ) that points to the site. (In a future post, I'll talk about how to make this code get the current site information dynamically. Update: See Constructing site URLs in ASP.NET Razor for info on how to create a non-hard-coded link.) The URL includes a query string value named confirmation that you add the token to. Because you're adding a token with who-knows-what characters in it into a URL, you need to URL-encode the token. (This changes characters like space to %20 and ampersand (&) to %26 so that they're not misinterpreted as reserved characters in the URL.)
The confirmationLink variable is the <a> element — i.e., the link — that you'll embed into the email body. Because the link has to contain double-quotation marks for the value of the href attribute, they're added as escaped characters (\"). (This is standard C#; sorry if I'm telling you something you already know.)
Next is the setup for email, which is done using the WebMail helper. This uses the values I listed earlier. (I obfuscated the ones I actually used.) In this example, I'm including the WebMail initialization code right here. It's much preferred, however, to put this initialization code into _AppStart.cshtml, right there next to the WebSecurity.InitializeDatabaseConnection call. You really only need to set these initialization properties once for the WebMail helper for your whole app, plus it makes it easier to change those values if you ever need to.
You actually send the email message by calling WebMail.Send , passing it various values that are specific to this message, like the recipient (the to property) and so on. Notice that the body property is set to the long string that includes the HTML markup for the message, including the confirmation link you set up earlier. Also notice that the isBodyHtml property is set to true — you're sending an HTML link as part of the message, so you want WebMail helper to send the message as HTML. (You're assuming that the user can get an HTML message; however, in case they can't, you're including the token as part of the body of the message, not just in the link.)
Finally, of course, you tell the user that you've sent them an email and that they have to finish the registration.
The complete listing for the registration-with-confirmation page is here.
The Confirmation Page When users click their confirmation link, it invokes (in my case, anyway) the ConfirmAccount.cshtml page. In that page, in theory all you need to do is you extract the query-string value (confirmation ) and then pass it to the WebSecurity.ConfirmAccount method. The basic code looks like this:
confirmationToken = Request["confirmation"]; if(!String.IsNullOrEmpty(confirmationToken)){ if( WebSecurity.ConfirmAccount(confirmationToken) ) { message = "Your account has been confirmed. Thanks!"; } else{ confirmationError = true; message = "There was problem while confirming your account."; } } Depending on how fancy you want to get, you can also accommodate the situation where the link that you sent to the user doesn't work. (Perhaps they can't get HTML-formatted emails.) For example, in the body of the page you can include a text box where users can enter the token and try confirming it that way:
@if(confirmationError == true){ <p>You can try entering your confirmation code here:<br/> <br/> <input type="text" value="" name="confirmation" /><br/> <br/> <input type="submit" value="Submit" name="buttonSubmit" /><br/> </p> } (No nice formatting here, sorry about that.) You can actually use the same code to process what they submit.
The complete listing for the confirmation page is here.
That's about it. As you can see, it requires only a little bit of effort beyond what you've already seen for absolutely basic login security.
|