What is the minimum ASP.NET provider implementation I need to get a user authenticated and authorized?

1k views Asked by At

By default ASP.NET MVC setups up the AccountController to use the SqlMembershipProvider, SqlProfileProvider and the SqlRoleProvider. I don't really need everything that brings to the table, in fact, it is more of a hassle to shape my data into that model.

What is the minimum I need to implement on the MembershipProvider, RoleProvider and ProfileProvider abstract classes to get authentication and authorization and not break some other dependency that might be there?

For instance, on the ProfileProvider it wants me to override the "FindInactiveProfilesByUserName" method, but I don't really care about this feature. Where is my app going to break when the NotImplementedException fires?

Additionally, on the MembershipProvider for instance, I don't need the FindUsersByEmail method. If I don't implement it will ASP.NET MVC choke at some point? If so, where?

3

There are 3 answers

0
Jeff Ogata On BEST ANSWER

As far as I know, ASP.NET MVC doesn't really do anything for you with regard to authentication. With that in mind, as @chrispr says, you should only need to implement ValidateUser, and the project created by the ASP.NET MVC project template only calls that method during authentication.

Regarding authorization, I took a look at AuthorizationAttribute in Reflector and found that it calls IPrincipal.IsInRole. Looking at System.Web.Security.RolePrincipal in Reflector, IsInRole calls GetRolesForUser, so you could try implementing only that method to start with.

I implemented custom providers for similar reasons (I don't like the schema the sql providers use), but I chose not to implement a custom profile provider since it seems to rely on configuration settings for the profile properties, and I didn't want to go that route (see ASP.NET Profile Properties Overview).

As a side note, I found that looking at the SqlMembershipProvider and SqlRoleProvider in Reflector was helpful when I implemented my own providers, so you might want to do the same.

0
chrispr On

I believe you only need to implement ValidateUser on the MembershipProvider to take advantage of the authentication features of the MembershipProvider. The rest of the features are invoked by provided web controls like CreateUserWizard, so make sure to disable any of the unsupported features on those controls when using them. As for the rest (RoleProvider and ProfileProvider), if you're not using any of the features related to User Roles or User Profiles, you don't have to implement any of the members.

0
abatishchev On

Here's what I have in my custom providers:

namespace MyProject
{
    public class SqlMembershipProvider : System.Web.Security.SqlMembershipProvider
    {
        private string ConnectionString { get; set; }

        public override bool ChangePassword(string userName, string oldPassword, string newPassword)
        {
            //
        }

        public overrideMembershipUser CreateUser(string userName, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
        {
            //
        }

        private MembershipUser CreateUser(string userName, string password, object providerUserKey, out MembershipCreateStatus status)
        {
            //
        }

        public override bool DeleteUser(string userName, bool deleteAllRelatedData)
        {
            //
        }

        public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
        {
            this.ConnectionString = ConfigurationManager.ConnectionStrings[config["connectionStringName"]].ConnectionString;

            base.Initialize(name, config);
        }

        public override MembershipUser GetUser(string userName, bool userIsOnline)
        {
            //
        }

        public override bool ValidateUser(string userName, string password)
        {
            //
        }
    }
}

and:

namespace MyProject
{
    public class SqlRoleProvider : System.Web.Security.RoleProvider
    {
        private string ConnectionString { get; set; }

        public override void AddUsersToRoles(string[] userNames, string[] roleNames)
        {
            //
        }

        public override string ApplicationName
        {
            get
            {
                throw new NotSupportedException();
            }
            set
            {
                throw new NotSupportedException();
            }
        }

        public override void CreateRole(string roleName)
        {
            throw new NotSupportedException();
        }

        public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
        {
            throw new NotSupportedException();
        }

        public override string[] FindUsersInRole(string roleName, string userNameToMatch)
        {
            throw new NotSupportedException();
        }

        public override string[] GetAllRoles()
        {
            //
        }

        public override string[] GetRolesForUser(string userName)
        {
            //
        }

        public override string[] GetUsersInRole(string roleName)
        {
            throw new NotSupportedException();
        }

        public override bool IsUserInRole(string userName, string roleName)
        {
            //
        }

        public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
        {
            this.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings[config["connectionStringName"]].ConnectionString;

            base.Initialize(name, config);
        }

        public override void RemoveUsersFromRoles(string[] userNames, string[] roleNames)
        {
            throw new NotSupportedException();
        }

        public override bool RoleExists(string roleName)
        {
            throw new NotSupportedException();
        }
    }
}