Is it possible to create a Logon System with ASP.NET MVC but not use the MembershipProvider?

asp.net MvcAuthentication

asp.net Mvc Problem Overview


I have an existing database with a users table, and we are planning to take the database and use it for a new system built in ASP.NET MVC. However, what I am uncertain about is whether or not I am able to create a login system that doesn't use the built in account controller or a regular membership provider so that we can still use the existing table structure.

So my question is, would this be possible? Or even particularly difficult to do if it is?

What is the most widely accepted way of doing things and the simplest?

asp.net Mvc Solutions


Solution 1 - asp.net Mvc

I had this exact same requirement. I had my own user and role schema and did not want to migrate to the asp.net membership schema but I did want to use the ASP.NET MVC action filters for checking authorization and roles. I had to do a fair amount of digging to find out exactly what needed to be done, but in the end it was relatively easy. I'll save you the trouble and tell you what I did.

  1. I created a class that derived from System.Web.Security.MembershipProvider. MembershipProvider has a ton of abstract methods for all sorts of authentication-related functions like forgot password, change password, create new user, etc. All I wanted was the ability to authenticate against my own schema. So my class contained mainly empty overrides. I just overrode ValidateUser:

    public override bool ValidateUser(string username, string password) { if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password)) return false;

     string hash = EncryptPassword(password);
     User user = _repository.GetByUserName(username);
     if (user == null) return false;
     
     return user.Password == hash;
    

    }

  2. I created a class that derived from System.Web.Security.RoleProvider. Again, I just had empty implementations for all the fluff I did not need like creating and changing roles. I just overrode two methods:

    public override string[] GetRolesForUser(string username) { User user = _repository.GetByUserName(username); string[] roles = new string[user.Role.Rights.Count + 1]; roles[0] = user.Role.Description; int idx = 0; foreach (Right right in user.Role.Rights) roles[++idx] = right.Description; return roles; }

    public override bool IsUserInRole(string username, string roleName) { User user = _repository.GetByUserName(username); if(user!=null) return user.IsInRole(roleName); else return false; }

  3. Then I plugged these two classes into my web.config:

That's it. The default authorization action filters will use these classes. You will still have to handle the login page sign in and sign off. Just use the standard forms authentication classes for this like you normally would.

Solution 2 - asp.net Mvc

Whenever anyone tells you that something security-related is "easy," they are nearly always wrong. There are a lot of subtleties in security which non-experts tend to miss.

In particular, any form of authentication which does not explicitly deal with caching is inherently broken. When an action result is cached, this happens within ASP.NET, not necessarily within the ASP.NET MVC stack. If you examine the source code for AuthorizeAttribute, you will see that it contains some slightly tricky but effective code to ensure that it always runs, even when the action result is cached.

The best way, by far, to customize ASP.NET MVC authentication is to write a custom ASP.NET membership provider. I won't claim that this is foolproof, but there are fewer ways to get in trouble with a broken security implementation in this route then with other methods. A substantial advantage of this technique is that you can substitute a different authorization system at almost any time, with no code changes.

If you must implement a custom MVC attribute, then you should subtype AuthorizeAttribute and override AuthorizeCore, taking careful note of the comments in the source code regarding thread safety.

Solution 3 - asp.net Mvc

Of course you can. I did it for my projects completely ignoring the membership provider.

You need to implement your own ActionFilter. Basically, it will intercepts control before a controller action is hit. Inside of it you decide whether to continue on to the action or redirect the user to login page.

For the attribute you can define any parameters you need to support your authentication/authorization model.

public class AuthorizationAttribute : ActionFilterAttribute, IActionFilter
{
   public MyRole UserRole { get; set; }

   void IActionFilter.OnActionExecuting (ActionExecutedContext filterContext)
   {
       // Decide whether to grant access to the action or redirect away
   }
}

[Authorization (UserRole = MyRole.All)]
public class UserController : Controller
{
    [Authorization (UserRole = MyRole.Admin)]
    public ActionResult Delete ()
    {
    }
}

Regarding the concerns expressed in the comments. Yes, enabling output cache will interfere with authorization. One just has to be aware of that.

Explanation of the problem: ASP.NET MVC Tip #40 - Don’t Cache Pages that Require Authorization

Solution 4 - asp.net Mvc

You have at least two possibilities

  • a custom action filter attribute that will provide your authorization check
  • a custom IHttpModule that will fill all the necessary data for the logged in user (including roles) and you can use existing action filters

The second choice can be used with regular web forms as well.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLiamGuView Question on Stackoverflow
Solution 1 - asp.net MvcMatt WrockView Answer on Stackoverflow
Solution 2 - asp.net MvcCraig StuntzView Answer on Stackoverflow
Solution 3 - asp.net Mvcuser151323View Answer on Stackoverflow
Solution 4 - asp.net MvcRobert KoritnikView Answer on Stackoverflow