Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I create a custom membership provider for ASP.NET MVC 2?

How do I create a custom membership for ASP.NET MVC 2 based on the ASP.NET membership provider?

like image 452
ilija veselica Avatar asked May 05 '10 06:05

ilija veselica


People also ask

How can I use ASP net membership provider?

The ASP.NET membership provider is a feature that enables ASP.NET developers to create Web sites that allow users to create unique user name and password combinations. With this facility, any user can establish an account with the site, and sign in for exclusive access to the site and its services.

What is provider MVC?

This article describes Custom Value Providers in MVC and their uses. Value Providers are the components that feed data to model binders. Feeding the data means installing the data to the Model binder for further use at the action level.


2 Answers

I have created a new project containing a custom membership provider and overrode the ValidateUser method from the MembershipProvider abstract class:

public class MyMembershipProvider : MembershipProvider {      public override bool ValidateUser(string username, string password)     {             // this is where you should validate your user credentials against your database.         // I've made an extra class so i can send more parameters          // (in this case it's the CurrentTerritoryID parameter which I used as          // one of the MyMembershipProvider class properties).           var oUserProvider = new MyUserProvider();           return oUserProvider.ValidateUser(username,password,CurrentTerritoryID);     } } 

Then I connected that provider to my ASP.NET MVC 2 project by adding a reference and pointing it out from my web.config:

<membership defaultProvider="MyMembershipProvider">     <providers>         <clear />         <add name="MyMembershipProvider"             applicationName="MyApp"             Description="My Membership Provider"             passwordFormat="Clear"             connectionStringName="MyMembershipConnection"             type="MyApp.MyMembershipProvider" />     </providers> </membership> 

I do need to create a custom class that inherits the RoleProvider abstract class and overrides the GetRolesForUser method. The ASP.NET MVC Authorizing uses that method to find out which roles are assigned to the current logged-on user and makes sure the user is permitted to access the controller action.

Here are the steps we need to take:

1) Create a custom class that inherits the RoleProvider abstract class and overrides the GetRolesForUser method:

public override string[] GetRolesForUser(string username) {     SpHelper db = new SpHelper();     DataTable roleNames = null;     try     {         // get roles for this user from DB...          roleNames = db.ExecuteDataset(ConnectionManager.ConStr,                     "sp_GetUserRoles",                     new MySqlParameter("_userName", username)).Tables[0];     }     catch (Exception ex)     {         throw ex;     }     string[] roles = new string[roleNames.Rows.Count];     int counter = 0;     foreach (DataRow row in roleNames.Rows)     {         roles[counter] = row["Role_Name"].ToString();         counter++;     }     return roles; } 

2) Connect the role provider with the ASP.NET MVC 2 application via our web.config:

<system.web> ...  <roleManager enabled="true" defaultProvider="MyRoleProvider">     <providers>         <clear />         <add name="MyRoleProvider"             applicationName="MyApp"             type="MyApp.MyRoleProvider"             connectionStringName="MyMembershipConnection" />     </providers> </roleManager>  ... </system.web> 

3) Set the Authorize(Roles="xxx,yyy") above the wanted Controller / Action:

[Authorization(Roles = "Customer Manager,Content Editor")] public class MyController : Controller {     ......  } 

That's it! Now it works!

4) Optional: set a custom Authorize attribute so we can redirect an unwanted role to an AccessDenied Page:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)] public class MyAuthorizationAttribute : AuthorizeAttribute {     /// <summary>     /// The name of the master page or view to use when rendering the view on authorization failure.  Default     /// is null, indicating to use the master page of the specified view.     /// </summary>     public virtual string MasterName { get; set; }      /// <summary>     /// The name of the view to render on authorization failure.  Default is "Error".     /// </summary>     public virtual string ViewName { get; set; }      public MyAuthorizationAttribute ()         : base()     {         this.ViewName = "Error";     }      protected void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus)     {         validationStatus = OnCacheAuthorization(new HttpContextWrapper(context));     }      public override void OnAuthorization(AuthorizationContext filterContext)     {         if (filterContext == null)         {             throw new ArgumentNullException("filterContext");         }          if (AuthorizeCore(filterContext.HttpContext))         {             SetCachePolicy(filterContext);         }         else if (!filterContext.HttpContext.User.Identity.IsAuthenticated)         {             // auth failed, redirect to login page             filterContext.Result = new HttpUnauthorizedResult();         }         else if (filterContext.HttpContext.User.IsInRole("SuperUser"))         {             // is authenticated and is in the SuperUser role             SetCachePolicy(filterContext);         }         else         {             ViewDataDictionary viewData = new ViewDataDictionary();             viewData.Add("Message", "You do not have sufficient privileges for this operation.");             filterContext.Result = new ViewResult { MasterName = this.MasterName, ViewName = this.ViewName, ViewData = viewData };         }     }      protected void SetCachePolicy(AuthorizationContext filterContext)     {         // ** IMPORTANT **         // Since we're performing authorization at the action level, the authorization code runs         // after the output caching module. In the worst case this could allow an authorized user         // to cause the page to be cached, then an unauthorized user would later be served the         // cached page. We work around this by telling proxies not to cache the sensitive page,         // then we hook our custom authorization code into the caching mechanism so that we have         // the final say on whether a page should be served from the cache.         HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;         cachePolicy.SetProxyMaxAge(new TimeSpan(0));         cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */);     } } 

Now we can use our own made attribute to redirect our users to access denied view:

[MyAuthorization(Roles = "Portal Manager,Content Editor", ViewName = "AccessDenied")] public class DropboxController : Controller {      ....... } 

That's it! Super duper!

Here are some of the links I've used to get all this info:

Custom role provider: http://davidhayden.com/blog/dave/archive/2007/10/17/CreateCustomRoleProviderASPNETRolePermissionsSecurity.aspx

I hope this info helps!

like image 198
danfromisrael Avatar answered Sep 29 '22 20:09

danfromisrael


This worked for me http://mattwrock.com/post/2009/10/14/Implementing-custom-Membership-Provider-and-Role-Provider-for-Authinticating-ASPNET-MVC-Applications.aspx

like image 44
uriDium Avatar answered Sep 29 '22 19:09

uriDium