WebSecurity in MVC
By Suraj Sahoo
on
Mar 03, 2015
In
this article, I would be discussing a very interesting topic called
WebSecurity in MVC application and how easy and simple it is to
implement and understand.
In this article I will be discussing a very interesting topic called Web Security in MVC applications and how easy and simple it is to implement and understand. Let me share a small incident for which I came across this concept. Usually we create an MVC application and select a template, it may be internet or empty (these two are used frequently). Based on these templates, the web project is scaffolded and we get the final project structure to work on. If we select an internet application then from the default scaffolding we get a Controller for "Home" and "Account" created. ASP.NET MVC by default provides the authentication using the Web Security. I tried to customize the way authentication was done and then realized this is so simple and easy, since it reduces so many lines of our codes. Let's discuss more on this with a small Demo.
Let's Play
Let's briefly become familiar wiht Web Security! According to MSDN, it provides security and authentication to ASP.Net web applications with many more features like user account creation, Login User and Log off, Reset & Change Password, using its in-built functions. It internally also does the Password hashing that is one of the main concerns during the creation of a user account. The various properties and methods are well explained in the MSDN link given above. This is usually called a Helper class that is present in the namespace "System.WebMatrix.WebData". When an internet template is chosen we would find the "Dynamic Link Library" , WebMatrix.WebData.dll. Let's create a new project in Visual Studio. Here I create a new ASP.Net Web Project and name it "WebSecurityDemo" and after clicking on OK the final creation of the project in Visual Studio looks as in the following:
As we can see in the preceding image, the project is scaffolded based on the internet template in MVC. This by default creates the Home controller and Account controller with many kinds of authentication and security. This default web application lacks any coding but gives the user options to Register, Login, Log off and OWIN authentication using Facebook, Twitter, G+ ( This requires some modification that I will be discussing later). But how does this happen? This is done by the Authorize attribute provided by MVC that is one of the best assets of MVC. Just specifying an attribute like "[Authorize]" that restricts the user access to the methods/actions if specified at the Controller level or also can be specified at the action level, just as in the following snippet:
- [Authorize]
- [InitializeSimpleMembership]
- public class AccountController : Controller
- {
- [AllowAnonymous]
- public ActionResult Login(string returnUrl)
- {
- ViewBag.ReturnUrl = returnUrl;
- return View();
- }
- }
- namespace WebSecurityDemoTest.Filters
- {
- public class WebSecurityAuthorize:AuthorizeAttribute
- {
- protected bool AuthorizeCore(HttpContextBase httpContext)
- {
- if (!httpContext.Request.IsAuthenticated)
- {
- return false;
- }
- if (HttpContext.Current.Session["SessionHelper"] == null)
- {
- return false;
- }
- return true;
- }
- protected void HandleUnauthorizedRequest(AuthorizationContext filterContext)
- {
- filterContext.Result = new RedirectResult("/");
- base.HandleUnauthorizedRequest(filterContext);
- }
- }
- }
- FormsAuthentication.SetAuthCookie(userName,true);
- using System;
- using System.Data.Entity;
- using System.Data.Entity.Infrastructure;
- using System.Threading;
- using System.Web.Mvc;
- using WebMatrix.WebData;
- using WebSecurityDemoTest.Models;
- namespace WebSecurityDemoTest.Filters
- {
- [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
- public sealed class InitializeSimpleMembershipAttribute : ActionFilterAttribute
- {
- private static SimpleMembershipInitializer _initializer;
- private static object _initializerLock = new object();
- private static bool _isInitialized;
- public override void OnActionExecuting(ActionExecutingContext filterContext)
- {
- // Ensure ASP.NET Simple Membership is initialized only once per app start
- LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);
- }
- private class SimpleMembershipInitializer
- {
- public SimpleMembershipInitializer()
- {
- Database.SetInitializer<UsersContext>(null);
- try
- {
- using (var context = new UsersContext())
- {
- if (!context.Database.Exists())
- {
- // Create the SimpleMembership database without Entity Framework migration schema
- ((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
- }
- }
- WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
- }
- catch (Exception ex)
- {
- throw new InvalidOperationException("The ASP.NET Simple Membership database could not be initialized. For more information, please see http://go.microsoft.com/fwlink/?LinkId=256588", ex);
- }
- }
- }
- }
- }
- WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
- Right-click on the Model folder. Select Add new Item:
- Then
select Data and add an ADO.Net Entity Data Model with a valid name. I
have named the data model WebSecurity.edmx. This creates the conceptual
model for the database after we provide the connection.
- Then
we need to specify the connection to the database. You can create a
sample database or use an existing one. I will be using one existing one
and will show how the tables for websecurity are generated. Select
Generate from database.
- Then
the connection needs to be set up. Choose your local server, so in the
database TextBox enter ". (Dot)" which means local DB and that would
list the databases present in your local. Choose anyone you wish to.
- Thus, when the connection is success and is established, we can find the connection string in the Web.Config file.
- Then
since you can scroll up and see in the InitializeSimpleMembership.cs we
have the DefaultConnection specified, we need to change the
configuration specified as the default in the web.config connection
string, that is change the Data Source =. And remove the
AttachedDbFileName entirely and then specify the Initial Catalog as the
database name that you have added during the db connection. Finally the
connection string with the name "DefaultConnection" looks as in:
- <add name="DefaultConnection" connectionString="Data Source=.;Initial Catalog=Customer;Integrated Security=SSPI;" providerName="System.Data.SqlClient" />
- Thus,
we have reached the end of the set up. Now clean and build the solution
once and then run. When we run the application, we land on the Home
page as the Home controller that has no authorization. And also remember
one thing, the membership/websecurity tables will only be created once
the InitializeSimpleMembership attribute is hit and in the preceding
snippets it is hit only when the Account controller is accessed. So when
we go to any action method that is Allow Anonymous as we also need to
land on the page, so we click on Register.
- The
following image shows the table created once the attribute is
hit/executed. "dbo.webpages_Membership" stores all the information
related to the user registered with the user password that is hashed and
that is one way to increase security. User Id acts as the foreign key
here to the UserId primary key in the UserProfile table that also
contains the UserName that is asked during the registration.
- After the registration, you will find yourself logged in as the UserName entered and the data in the tables would look like:
- Thus this is how the simple attribute, internally does everything.
- WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe)
- WebSecurity.ChangePassword(User.Identity.Name, model.OldPassword, model.NewPassword)
- WebSecurity.CreateUserAndAccount (model.UserName, model.Password)
Conclusion
Thus, I discussed in this article the details of the WebSecurity class and how to use that in a MVC application. The method and the membership authentication is the same, we just need to customize to have our own hold over it. It is very easy to use and that makes the code less redundant and reusable and mainly maintainable. This follows the DRY concept, Don't Repeat Yourself. Thus this suggests using everything once, like have an Authorize attribute may it be Custom and reuse it wherever required. WebSecurity has everything defined, we just need to explore and use its methods and properties extensively to reduce the level of coding and LOC. Thus here I end my article, I hope I have at least explained something. Though I am not an expert and moreover a human, mistakes are inevitable. I will be happy to know about any mistakes you find. Suggestions and discussions are most welcome. Share and learn.
Suraj Sahoo
Proud
Indian | jsfiddler | Cricketer | Software Developer Suraj Sahoo is a
Software Engineer at Mindfire Solutions, India
(http://www.mindfiresolutions.com/). He has been awarded by Dzone.com
with the Most Valu... Read more
Personal Blog: http://surajpassion.in
- rank218
- 41.4 k readers
- StarterMember
No comments:
Post a Comment