This tutorial shows you how to build a secure ASP.NET MVC 4 web application that enables users to log in with credentials from Facebook, Yahoo, and Google. You will also deploy the application to Windows Azure.
You can open a Windows Azure account for free, and if you don't already have Visual Studio 2012, the SDK automatically installs Visual Studio 2012 for Web Express. You can start developing for Windows Azure for free.
This tutorial assumes that you have no prior experience using Windows Azure. On completing this tutorial, you'll have a secure data-driven web application up and running in the cloud and using a cloud database.
You'll learn:
- How to enable your machine for Windows Azure development by installing the Windows Azure SDK.
- How to create a secure ASP.NET MVC 4 project and publish it to a Windows Azure Web Site.
- How to use OAuth and the ASP.NET membership database to secure your application.
- How to deploy a membership database to Windows Azure.
- How to use a SQL database to store data in Windows Azure.
- How to use Visual Studio to update and manage the membership database on SQL Azure.
You'll build a simple contact list web application that is built on ASP.NET MVC 4 and uses the ADO.NET Entity Framework for database access. The following illustration shows the login page for the completed application:
In this tutorial:
- Set up the development environment
- Set up the Windows Azure environment
- Create an ASP.NET MVC 4 application
- Deploy the application to Windows Azure
- Add a database to the application
- Add an OAuth Provider
- Add Roles to the Membership Database
- Create a Data Deployment Script
- Deploy the app to Windows Azure
- Update the Membership Database
Set up the development environment
To start, set up your development environment by installing the Windows Azure SDK for the .NET Framework.
- To install the Windows Azure SDK for .NET, click the link below. If you don't have Visual Studio 2012 installed yet, it will be installed by the link. This tutorial requires Visual Studio 2012.
Get Tools and SDK for Visual Studio 2012 - When you are prompted to run or save vwdorvs11azurepack.exe, click Run.
When the installation is complete, you have everything necessary to start developing.
Set up the Windows Azure environment
Next, set up the Windows Azure environment by creating a Windows Azure Web Site and a SQL database.
Create a web site and a SQL database in Windows Azure
Your Windows Azure Web Site will run in a shared hosting environment, which means it runs on virtual machines (VMs) that are shared with other Windows Azure clients. A shared hosting environment is a low-cost way to get started in the cloud. Later, if your web traffic increases, the application can scale to meet the need by running on dedicated VMs. If you need a more complex architecture, you can migrate to a Windows Azure Cloud Service. Cloud services run on dedicated VMs that you can configure according to your needs.
Windows Azure SQL Database is a cloud-based relational database service that is built on SQL Server technologies. The tools and applications that work with SQL Server also work with SQL Database.
- In the Windows Azure Management Portal, click Web Sites in the left tab, and then click New.
- Click CUSTOM CREATE.
The New Web Site - Custom Create wizard opens. - In the New Web Site step of the wizard, enter a string in the URL box to use as the unique URL for your application. The complete URL will consist of what you enter here plus the suffix that you see next to the text box. The illustration shows "contactmgr2", but that URL is probably taken so you will have to choose a different one.
- In the Database drop-down list, choose Create a new SQL database.
- In the Region drop-down list, choose the same region you selected for the Web site.
This setting specifies which data center your VM will run in. In the DB CONNECTION STRING NAME, enter connectionString1. - Click the arrow that points to the right at the bottom of the box. The wizard advances to the Database Settings step.
- In the Name box, enter ContactDB.
- In the Server box, select New SQL Database server. Alternatively, if you previously created a SQL Server database, you can select that SQL Server from the dropdown control.
- Enter an administrator LOGIN NAME and PASSWORD. If you selected New SQL Database server you aren't entering an existing name and password here, you're entering a new name and password that you're defining now to use later when you access the database. If you selected a SQL Server you’ve created previously, you’ll be prompted for the password to the previous SQL Server account name you created. For this tutorial, we won't check the *Advanced * box. The *Advanced * box allows you to set the DB size (the default is 1 GB but you can increase this to 150 GB) and the collation.
- Click the check mark at the bottom of the box to indicate you're finished.
The following image shows using an existing SQL Server and Login.
The Management Portal returns to the Web Sites page, and the Status column shows that the site is being created. After a while (typically less than a minute), the Status column shows that the site was successfully created. In the navigation bar at the left, the number of sites you have in your account appears next to the Web Sites icon, and the number of databases appears next to the SQL Databases icon.
Create an ASP.NET MVC 4 application
You have created a Windows Azure Web Site, but there is no content in it yet. Your next step is to create the Visual Studio web application project that you'll publish to Windows Azure.
Create the project
- Start Visual Studio 2012.
- From the File menu click New Project.
- In the New Project dialog box, expand Visual C# and select Web under Installed Templates and then select ASP.NET MVC 4 Web Application. Keep the default .NET Framework 4.5. Name the application ContactManager and click OK.
- In the New ASP.NET MVC 4 Project dialog box, select the Internet Application template. Keep the default Razor View Engine and then click OK.
Set the page header and footer
- In Solution Explorer, expand the Views\Shared folder and open the _Layout.cshtml file.
- Replace each occurrence of "My ASP.NET MVC Application" with "Contact Manager".
- Replace "your logo here" with "CM Demo".
Run the application locally
This is all you need to do for now to create the application that you'll deploy to Windows Azure. Later you'll add database functionality.
Deploy the application to Windows Azure
- In your browser, open the Windows Azure Management Portal.
- In the Web Sites tab, click the name of the site you created earlier.
- On the right side of the window, click Download publish profile.
This step downloads a file that contains all of the settings that you need in order to deploy an application to your Web Site. You'll import this file into Visual Studio so you don't have to enter this information manually. - Save the .publishsettings file in a folder that you can access from Visual Studio.
Security Note: The .publishsettings file contains your credentials (unencoded) that are used to administer your Windows Azure subscriptions and services. The security best practice for this file is to store it temporarily outside your source directories (for example in the Libraries\Documents folder), and then delete it once the import has completed. A malicious user gaining access to the publishsettings file can edit, create, and delete your Windows Azure services. - In Visual Studio, right-click the project in Solution Explorer and select Publish from the context menu.
The Publish Web wizard opens. - In the Profile tab of the Publish Web wizard, click Import.
- Select the publishsettings file you downloaded earlier, and then click Open.
- In the Connection tab, click Validate Connection to make sure that the settings are correct. When the connection has been validated, a green check mark is shown next to the Validate Connection button.
- Click Next.
- In the Settings tab, click Next.
You can accept all of the default settings on this page. You are deploying a Release build configuration and you don't need to delete files at the destination server. The UsersContext (DefaultConnection) entry under Databases is created because of the UsersContext : DbContext class which uses the DefaultConnection string - In the Preview tab, click Start Preview.
The tab displays a list of the files that will be copied to the server. Displaying the preview isn't required to publish the application but is a useful function to be aware of. In this case, you don't need to do anything with the list of files that is displayed. - Click Publish.
Visual Studio begins the process of copying the files to the Windows Azure server. The Output window shows what deployment actions were taken and reports successful completion of the deployment. - The default browser automatically opens to the URL of the deployed site.
The application you created is now running in the cloud. The next time you deploy the application, only the changed (or new) files will be deployed.
Add a database to the application
Next, you'll update the MVC application to add the ability to display and update contacts and store the data in a database. The application will use the Entity Framework to create the database and to read and update data in the database.
Add data model classes for the contacts
You begin by creating a simple data model in code.
In Solution Explorer, right-click the Models folder, click Add, and then Class.
In the Add New Item dialog box, name the new class file Contact.cs, and then click Add.
Replace the contents of the Contacts.cs file with the following code.
using System.ComponentModel.DataAnnotations; using System.Globalization; namespace ContactManager.Models { public class Contact { public int ContactId { get; set; } public string Name { get; set; } public string Address { get; set; } public string City { get; set; } public string State { get; set; } public string Zip { get; set; } [DataType(DataType.EmailAddress)] public string Email { get; set; } } }
The Contacts class defines the data that you will store for each contact, plus a primary key, ContactID, that is needed by the database.
Create web pages that enable app users to work with the contacts
The ASP.NET MVC scaffolding feature can automatically generate code that performs create, read, update, and delete (CRUD) actions.
Add a Controller and a view for the data
- Build the project (Ctrl+Shift+B). (You must build the project before using scaffolding mechanism.)
- In Solution Explorer, right-click the Controllers folder and click Add, and then click Controller....
- In the Add Controller dialog box, enter "HomeController" as your controller name.
- Set the Scaffolding options Template to MVC Controller with read/write actions and views, using Entity Framework.
- Select Contact as your model class and <New data context...> as your data context class.
- On the New Data Context dialog box, accept the default value ContactManager.Models.ContactManagerContext.
- Click OK, then click Add in the Add Controller dialog box.
- On the Add Controller overwrite dialog, make sure all options are checked and click OK.
Visual Studio creates a controller methods and views for CRUD database operations for Contact objects.
Enable Migrations, create the database, add sample data and a data initializer
The next task is to enable the Code First Migrations feature in order to create the database based on the data model you created.
- In the Tools menu, select Library Package Manager and then Package Manager Console.
In the Package Manager Console window, enter the following command:
enable-migrations -ContextTypeName ContactManagerContext
You must specify the context type name (ContactManagerContext) because the project contains two DbContext derived classes, the ContactManagerContext we just added and the UsersContext, which is used for the membership database. The ContactManagerContext class was added by the Visual Studio scaffolding wizard.
The enable-migrations command creates a Migrations folder and it puts in that folder a Configuration.cs file that you can edit to configure Migrations.In the Package Manager Console window, enter the following command:
add-migration Initial
The add-migration Initial command generates a file named <date_stamp>Initial in the Migrations folder that creates the database. The first parameter ( Initial ) is arbitrary and is used to create the name of the file. You can see the new class files in Solution Explorer.
In the Initial class, the Up method creates the Contacts table, and the Down method (used when you want to return to the previous state) drops it.- Open the Migrations\Configuration.cs file.
Add the following namespaces.
using ContactManager.Models;
Replace the Seed method with the following code:
protected override void Seed(ContactManager.Models.ContactManagerContext context) { context.Contacts.AddOrUpdate(p => p.Name, new Contact { Name = "Debra Garcia", Address = "1234 Main St", City = "Redmond", State = "WA", Zip = "10999", Email = "debra@example.com", }, new Contact { Name = "Thorsten Weinrich", Address = "5678 1st Ave W", City = "Redmond", State = "WA", Zip = "10999", Email = "thorsten@example.com", }, new Contact { Name = "Yuhong Li", Address = "9012 State st", City = "Redmond", State = "WA", Zip = "10999", Email = "yuhong@example.com", }, new Contact { Name = "Jon Orton", Address = "3456 Maple St", City = "Redmond", State = "WA", Zip = "10999", Email = "jon@example.com", }, new Contact { Name = "Diliana Alexieva-Bosseva", Address = "7890 2nd Ave E", City = "Redmond", State = "WA", Zip = "10999", Email = "diliana@example.com", } ); }
This code above will initialize the database with the contact information. For more information on seeding the database, see Seeding and Debugging Entity Framework (EF) DBs.
In the Package Manager Console enter the command:
update-database
The update-database runs the first migration which creates the database. By default, the database is created as a SQL Server Express LocalDB database. (Unless you have SQL Server Express installed, in which case the database is created using the SQL Server Express instance.)
Press CTRL+F5 to run the application.
The application shows the seed data and provides edit, details and delete links.
OAuthAdd an OAuth Provider
OAuth is an open protocol that allows secure authorization in a simple and standard method from web, mobile, and desktop applications. The ASP.NET MVC internet template uses OAuth to expose Facebook, Twitter, Google, Yahoo, and Microsoft as authentication providers. Although this tutorial uses only Facebook, Google, and Yahoo as the authentication providers, you can easily modify the code to use any of the providers. The steps to implement other providers are very similar to the steps you will see in this tutorial.
In addition to authentication, the tutorial will also use roles to implement authorization. Only those users you add to the canEdit role will be able to create, edit, or delete contacts.
Registering with an external provider
To authenticate users with credentials from some external providers, you must register your web site with the provider and obtain a key and connection secret. Google and Yahoo don't require you to register and obtain keys.
This tutorial does not show all of the steps you must perform to register with these providers. The steps are typically not difficult. To successfully register your site, follow the instructions provided on those sites. To get started with registering your site, see the developer site for:
Navigate to https://developers.facebook.com/apps page and log in if necessary. Click the Register as a Developer button and complete the registration process. Once you complete registration, click Create New App. Enter a name for the app. You don't need to enter an app namespace.
Enter localhost for the App Domain and http://localhost/ for the Site URL. Click Enabled for Sandbox Mode, then click Save Changes.
You will need the App ID and the App Secret to implement OAuth in this application.
Creating test users
In the left pane under Settings click Developer Roles. Click the Create link on the Test Users row (not the Testers row).
Click on the Modify link to get the test users email (which you will use to log into the application). Click the See More link, then click Edit to set the test users password.
Adding application id and secret from the provider
Open the App_Start\AuthConfig.cs file. Remove the comment characters from the RegisterFacebookClient method and add the app id and app secret. Use the values you obtained, the values shown below will not work. Remove the comment characters from the OAuthWebSecurity.RegisterGoogleClient call and add the OAuthWebSecurity.RegisterYahooClient as shown below. The Google and Yahoo providers don't require you to register and obtain keys.
Warning: Keep your app ID and secret secure. A malicious user who has your app ID and secret can pretend to be your application.
public static void RegisterAuth()
{
OAuthWebSecurity.RegisterFacebookClient(
appId: "enter numeric key here",
appSecret: "enter numeric secret here");
OAuthWebSecurity.RegisterGoogleClient();
OAuthWebSecurity.RegisterYahooClient();
}
- Run the application and click the Log In link.
- Click the Facebook button.
- Enter your Facebook credentials or one of the test users credentials.
- Click Okay to allow the application to access your Facebook resources.
- You are redirected to the Register page. If you logged in using a test account, you can change the user name to something shorter, for example "Bill FB test". Click the Register button which will save the user name and email alias to the membership database.
- Register another user. Currently a bug in the log in system prevents you from logging off and logging in as another user using the same provider (that is, you can't log off your Facebook account and log back in with a different Facebook account). To work around this, navigate to the site using a different browser and register another user. One user will be added to the manager role and have edit access to application, the other user will only have access to non-edit methods on the site. Anonymous users will only have access to the home page.
- Register another user using a different provider.
- Optional: You can also create a local account not associated with one of the providers. Later on in the tutorial we will remove the ability to create local accounts. To create a local account, click the Log out link (if you are logged in), then click the Register link. You might want to create a local account for administration purposes that is not associated with any external authentication provider.
Add Roles to the Membership Database
In this section you will add the canEdit role to the membership database. Only those users in the canEdit role will be able to edit data. A best practice is to name roles by the actions they can perform, so canEdit is preferred over a role called admin. When your application evolves you can add new roles such as canDeleteMembers rather than superAdmin.
- In the View menu click Database Explorer if you are using Visual Studio Express for Web or Server Explorer if you are using full Visual Studio.
- In Server Explorer, expand DefaultConnection then expand Tables.
- Right click UserProfile and click Show Table Data.
- Record the UserId for the user that will have the canEdit role. In the image below, the user ricka with UserId 2 will have the canEdit role for the site.
- Right click webpages_Roles and click Show Table Data.
- Enter canEdit in the RoleName cell. The RoleId will be 1 if this is the first time you've added a role. Record the RoleID. Be sure there is not a trailing space character, "canEdit " in the role table will not match "canEdit" in the controller code.
- Right click webpages UsersInRoles and click Show Table Data. Enter the UserId for the user you want to grant canEdit access and the RoleId.
The webpages_OAuthMembership table contains the OAuth provider, the provider UserID and the UserID for each registered OAuth user. The webpages-Membership table contains the ASP.NET membership table. You can add users to this table using the register link. It's a good idea to add a user with the canEdit role that is not associated with Facebook or another third party authorization provider so that you can always have canEdit access even when the third party authorization provider is not available. Later on in the tutorial we will disable ASP.NET membership registration.
Protect the Application with the Authorize Attribute
In this section we will apply the Authorize attribute to restrict access to the action methods. Anonymous user will be able to view the home page only. Registered users will be able to see contact details, the about and the contacts pages. Only users in the canEdit role will be able to access action methods that change data.
Add the Authorize filter and the RequireHttps filter to the application. An alternative approach is to add the Authorize attribute and the RequireHttps attribute to each controller, but it's considered a security best practice to apply them to the entire application. By adding them globally, every new controller and action method you add will automatically be protected, you won't need to remember to apply them. For more information see Securing your ASP.NET MVC 4 App and the new AllowAnonymous Attribute. Open the App_Start\FilterConfig.cs file and replace the RegisterGlobalFilters method with the following.
public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); filters.Add(new System.Web.Mvc.AuthorizeAttribute()); filters.Add(new RequireHttpsAttribute()); }
Add the AllowAnonymous attribute to the Index method. The AllowAnonymous attribute enables you to whitelist the methods you want to opt out of authorization.
- Add [Authorize(Roles = "canEdit")] to the Get and Post methods that change data (Create, Edit, Delete).
Add the About and Contact methods. A portion of the completed code is shown below.
public class HomeController : Controller { private ContactManagerContext db = new ContactManagerContext(); [AllowAnonymous] public ActionResult Index() { return View(db.Contacts.ToList()); }
public ActionResult About() { return View(); } public ActionResult Contact() { return View(); } [Authorize(Roles = "canEdit")] public ActionResult Create() { return View(); } // Methods moved and omitted for clarity.
}
Remove ASP.NET membership registration. The current ASP.NET membership registration in the project does not provide support for password resets and it does not verify that a human is registering (for example with a CAPTCHA). Once a user is authenticated using one of the third party providers, they can register. In the AccountController, remove the [AllowAnonymous] from the GET and POST Register methods. This will prevent bots and anonymous users from registering.
- In the Views\Shared_LoginPartial.cshtml, remove the Register action link.
- Enable SSL. In Solution Explorer, click the ContactManager project, then click F4 to bring up the properties dialog. Change SSL Enabled to true. Copy the SSL URL.
- In Solution Explorer, right click the Contact Manager project and click Properties.
- In the left tab, click Web.
- Change the Project Url to use the SSL URL.
- Click Create Virtual Directory.
- Press CTRL+F5 to run the application. The browser will display a certificate warning. For our application you can safely click on the link Continue to this website. Verify only the users in the canEdit role can change data. Verify anonymous users can only view the home page.
Windows Azure Web sites include a valid security certificate, so you won't see this warning when you deploy to Azure.
Create a Data Deployment Script
The membership database isn't managed by Entity Framework Code First so you can't use Migrations to deploy it. We'll use the dbDacFx provider to deploy the database schema, and we'll configure the publish profile to run a script that will insert initial membership data into membership tables.
This tutorial will use SQL Server Management Studio (SSMS) to create data deployment scripts.
Install SSMS from Microsoft SQL Server 2012 Express Download Center:
- ENU\x64\SQLManagementStudiox64ENU.exe for 64 bit systems.
ENU\x86\SQLManagementStudiox86ENU.exe for 32 bit systems.
If you choose the wrong one for your system it will fail to install and you can try the other one.
(Note that this is a 600 megabyte download. It may take a long time to install and may require a reboot of your computer.)
On the first page of the SQL Server Installation Center, click New SQL Server stand-alone installation or add features to an existing installation, and follow the instructions, accepting the default choices. The following image shows the step that install SSMS.
Create the development database script
- Run SSMS.
- In the Connect to Server dialog box, enter (localdb)\v11.0 as the Server name, leave Authentication set to Windows Authentication, and then click Connect. If you have installed SQL Express, enter .\SQLEXPRESS.
- In the Object Explorer window, expand Databases, right-click aspnet-ContactManager, click Tasks, and then click Generate Scripts.
- In the Generate and Publish Scripts dialog box, click Set Scripting Options. You can skip the Choose Objects step because the default is Script entire database and all database objects and that is what you want.
- Click Advanced.
- In the Advanced Scripting Options dialog box, scroll down to Types of data to script, and click the Data only option in the drop-down list. (See the image below the next step.)
- Change Script USE DATABASE to False. USE statements aren't valid for Windows Azure SQL Database and aren't needed for deployment to SQL Server Express in the test environment.
- Click OK.
- In the Generate and Publish Scripts dialog box, the File name box specifies where the script will be created. Change the path to your solution folder (the folder that has your Contacts.sln file) and change the file name to aspnet-data-membership.sql.
- Click Next to go to the Summary tab, and then click Next again to create the script.
- Click Finish.
Deploy the app to Windows Azure
- Open the application root Web.config file. Find the DefaultConnection markup, and then copy and paste it under the DefaultConnection markup line. Rename the copied element DefaultConnectionDeploy. You will need this connection string to deploy the user data in the membership database.
- Build the application.
- In Visual Studio, right-click the project in Solution Explorer and select Publish from the context menu.
The Publish Web wizard opens. - Click the Settings tab. Click the v icon to select the Remote connection string for the ContactManagerContext and DefaultConnectionDeploy. The three Databases listed will all use the same connection string. The ContactManagerContext database stores the contacts, the DefaultConnectionDeploy is used only to deploy the user account data to the membership database and the UsersContext database is the membership database.
- Under ContactManagerContext, check Execute Code First Migrations.
- Under DefaultConnectionDeploy check Update database then click the Configure database updates link.
- Click the Add SQL Script link and navigate to the aspnet-data-membership.sql file. You only need to do this once. The next deployment you uncheck Update database because you won't need to add the user data to the membership tables.
- Click Publish.
- Navigate to the https://developers.facebook.com/apps page and change the App Domains and Site URL settings to the Windows Azure URL.
- Test the application. Verify only the users in the canEdit role can change data. Verify anonymous users can only view the home page. Verify authenticated users can navigate to all links that don't change data.
- The next time you publish the application be sure to uncheck Update database under DefaultConnectionDeploy.
Update the Membership Database
Once the site is deployed to Windows Azure and you have more registered users you might want to make some of them members of the canEdit role. In this section we will use Visual Studio to connect to the SQL Azure database and add users to the canEdit role.
- In Solution Explorer, right click the project and click Publish.
- Click the Settings tab.
- Copy the connection string. For example, the connection string used in this sample is: Data Source=tcp:d015leqjqx.database.windows.net,1433; Initial Catalog=ContactDB2;User Id=ricka0@d015lxyze;Password=xyzxyz
- Close the publish dialog.
- In the View menu click Database Explorer if you are using Visual Studio Express for Web or Server Explorer if you are using full Visual Studio.
- Click on the Connect to Database icon.
- If you are prompted for the Data Source, click Microsoft SQL Server.
- Copy and paste the Server Name, which starts with tcp (see the image below).
- Click Use SQL Server Authentication
- Enter your User name and Password, which are in the connection string you copied.
- Enter the database name (ContactDB, or the string after "Initial Catalog=" in the database if you didn't name it ContactDB.) If you get an error dialog, see the next section.
- Click Test Connection. If you get an error dialog, see the next section.
Cannot open server login error
If you get an error dialog stating "Cannot open server" you will need to add your IP address to the allowed IPs.
- In the Windows Azure Portal, Select SQL Databases in the left tab.
- Select the database you wish to open.
- Click the Set up Windows Azure firewall rules for this IP address link.
- When you are prompted with "The current IP address xxx.xxx.xxx.xxx is not included in existing firewall rules. Do you want to update the firewall rules?", click Yes. Adding this address is often not enough, you will need to add a range of IP addresses.
Adding a Range of Allowed IP Addresses
- In the Windows Azure Portal, Click SQL Databases.
- Click the Server hosting your Database.
- Click Configure on the top of the page.
- Add a rule name, starting and ending IP addresses.
- At the bottom of the page, click Save.
- You can now edit the membership database using the steps previously shown.
Next Steps
To get the colorful Facebook, Google and Yahoo log on buttons, see the blog post Customizing External Login Buttons in ASP.NET MVC 4. Another way to store data in a Windows Azure application is to use Windows Azure storage, which provide non-relational data storage in the form of blobs and tables. The following links provide more information on ASP.NET MVC and Window Azure.
- .NET Multi-Tier Application Using Storage Tables, Queues, and Blobs.
- Intro to ASP.NET MVC 4
- Getting Started with Entity Framework using MVC
- OAuth 2.0 and Sign-In
This tutorial and the sample application was written by Rick Anderson (Twitter @RickAndMSFT) with assistance from Tom Dykstra, Tom FitzMacken and Barry Dorrans (Twitter @blowdart).
Please leave feedback on what you liked or what you would like to see improved, not only about the tutorial itself but also about the products that it demonstrates. Your feedback will help us prioritize improvements. We are especially interested in finding out how much interest there is in more automation for the process of configuring and deploying the membership database.