using ASP.NET MVC 2 membership with my own database users / roles tables

Hello there
i wanna use ASP.NET MVC 2 membership with my own database users / roles tables
any idea how to do so?

when i open a new project i get an Account Controller that handles the LogOn scene. i'm not too familiar with the membership API but i do know that it create it's own DB file or DB schema in an existing DB.
however, that's not the case i need. i have my own users & roles tables that i need to access and validate.

i'll be happy to know how to do so using the existing mvc 2 + membership infrastructure .

Thanks Ahead,
Dan
maatayimAsked:
Who is Participating?
 
jamesbaileConnect With a Mentor Commented:
If you have your own database schema then you need to implement your own membership provider.

http://www.asp.net/(S(ywiyuluxr3qb2dfva1z5lgeg))/learn/videos/video-189.aspx

and the following

http://mvcmembership.codeplex.com/

for an MVC implementation.
0
 
maatayimAuthor Commented:
thanks! the links did help but i still didn't understand what are the specific methods i should override for enabling the MVC 2 filters (i specifically need the [Authorize(Roles="xxx")] attribute)

i wanna be able to use this from my own DB (I have Users table, Roles Table and UsersRoles Table):

[Authorize(Roles="Admin,Registered")]
public ActionResult Hello()
{
     return View();
}

Thanks!
0
 
jamesbaileCommented:
The authorise attribute checks the logged on users identity and membership groups and allows access to the action accordingly.

I'm not exactly sure what your question is.
0
Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
maatayimAuthor Commented:
yes, with the help of your links i have created a new project where i created a custom memebership provider and overriden the "ValidateUser" method that i intherited from the MembershipProvider abstract class:

public class MyMembershipProvider : MembershipProvider
    {        

        public override bool ValidateUser(string username, string password)
        {    
            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>

so far so good.
i got my AccountController LogOn Action working just fine with logging into the system.
so now i can get Authorized users inside and decide which Actions they can use by using the [Authorize] attribute above Actions(methods).

I did all that actually by overriding one method from the MembershipProvider abstract class (ValidateUser).

my question is: What method from which abstract class should i override so i can use the [Authorize(Roles="blabla")] attribute to let only specific roles use certain Actions (methods).

i've tried to look in the RoleProvider abstract class and couldnt if MVC uses that class and one of it's methods for the Authorize(roles="...") attribute.

i'd appreciate any help
thanks !
:-D
0
 
jamesbaileCommented:
In your LogOn action you need to make sure that you call FormsAuth.SignIn which should ensure that your session then knows which roles the user is a member of. As long as you've got that bit then the Authorize attribute should just work - provided the roles you specify match those that you have setup in your membership system.
0
 
maatayimAuthor Commented:
ok i've found the answer!
i do need to create a custom Role Provider 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 currnent logedOn 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 Role Provider 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 = "Portal 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 DropboxAuthorizationAttribute()
            : 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!

thanks for the help!
here are some of the links i've used to get all this info:

custom membership provider:
http://davidhayden.com/blog/dave/archive/2007/10/11/CreateCustomMembershipProviderASPNETWebsiteSecurity.aspx

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

custom authorization attribute:
http://stackoverflow.com/questions/1279643/asp-net-mvc-redirect-to-an-access-denied-page-using-a-custom-role-provider

and

http://stackoverflow.com/questions/977071/redirecting-unauthorized-controller-in-asp-net-mvc

and of course the leads you gave me

thanks for the help and i hope this info helps!
:-Dan

public class VAMPRoleProvider : RoleProvider
{
    public override string[] GetRolesForUser(string username)
        {
            SpHelper db = new SpHelper();
            DataTable roleNames = null;
            try
            {
               // Get roles 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;
        }
}

Open in new window

0
 
jamesbaileCommented:
Without the information provided the issue would not have been solved - in my book that is a solution to the problem and points should be awarded.

It appears to me that the original solution led to another question about roles and role providers.
0
 
maatayimAuthor Commented:
you're right
at the begining i didnt know that role provider is  different than the membership provider (i thought its the same one).
anyways thanks for the help
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.