I am in the same boat as you - I always hated RoleProviders. Yes, they are great if you want to put things on a small website, but they are not very realistic. The main drawback I have always found is that they bind you directly to ASP.NET.
The way I went on a recent project is to identify a pair of interfaces that are part of the service level (NOTE: I simplified them quite a bit, but you can easily add to them):
public interface IAuthenticationService { bool Login(string username, string password); void Logout(User user); } public interface IAuthorizationService { bool Authorize(User user, Roles requiredRoles); }
Then your users can have a Roles listing:
public enum Roles { Accounting = 1, Scheduling = 2, Prescriptions = 4
For your IAuthenticationService , you can have a basic implementation that does standard password verification, and then you can have a FormsAuthenticationService that does a little more, like setting a cookie, etc. For your AuthorizationService d you need something like this:
public class AuthorizationService : IAuthorizationService { public bool Authorize(User userSession, Roles requiredRoles) { if (userSession.IsAdministrator) { return true; } else {
In addition to these basic services, you can easily add services to reset passwords, etc.
Since you are using MVC, you can do authorization at the action level using ActionFilter :
public class RequirePermissionFilter : IAuthorizationFilter { private readonly IAuthorizationService authorizationService; private readonly Roles permissions; public RequirePermissionFilter(IAuthorizationService authorizationService, Roles requiredRoles) { this.authorizationService = authorizationService; this.permissions = requiredRoles; this.isAdministrator = isAdministrator; } private IAuthorizationService CreateAuthorizationService(HttpContextBase httpContext) { return this.authorizationService ?? new FormsAuthorizationService(httpContext); } public void OnAuthorization(AuthorizationContext filterContext) { var authSvc = this.CreateAuthorizationService(filterContext.HttpContext);
What you can decorate on your controller actions:
[RequirePermission(Roles.Accounting)] public ViewResult Index() {
The advantage of this approach is that you can also use dependency injection and an IoC container to connect to the network. In addition, you can use it for several applications (and not just for ASP.NET). You must use ORM to determine the appropriate schema.
If you need more information about FormsAuthorization/Authentication services or where to go from here, let me know.
EDIT: To add a "security trim" you can do this with HtmlHelper. It probably needs a little more ... but you get the idea.
public static bool SecurityTrim<TModel>(this HtmlHelper<TModel> source, Roles requiredRoles) { var authorizationService = new FormsAuthorizationService(); var user = (User)HttpContext.Current.Session["CurrentUser"]; return authorizationService.Authorize(user, requiredRoles); }
And then inside your view (using Razor syntax here):
@if(Html.SecurityTrim(Roles.Accounting)) { <span>Only for accounting</span> }
EDIT: UserSession will look something like this:
public class UserSession { public int UserId { get; set; } public string UserName { get; set; } public bool IsAdministrator { get; set; } public Roles GetRoles() {
Thus, we do not disclose the password hash and all other details inside the session of the current user, since they really are not needed for the life of the user's session.