I have created a custom role provider for my MVC4 application where I have been successfully able to override CreateRole, GetAllRoles and RoleExists methods and link them to my existing database as follows:
namespace Project.Providers
{
public class MyProvider : System.Web.Security.SqlRoleProvider
{
private MyContext dbcontext = new MyContext(System.Configuration.ConfigurationManager.ConnectionStrings["MyContext"].ConnectionString);
private Repository<MyUser> userRepository;
private Repository<Role> roleRepository;
public MyProvider()
{
this.userRepository = new Repository<MyUser>(dbcontext);
this.roleRepository = new Repository<Role>(dbcontext);
}
public override string[] GetAllRoles()
{
IEnumerable<Role> dbRoles = roleRepository.GetAll();
int dbRolesCount = roleRepository.GetAll().Count();
string[] roles = new string[dbRolesCount];
int i = 0;
foreach(var role in dbRoles)
{
roles[i] = role.Name;
i++;
}
return roles;
}
public override bool RoleExists(string roleName)
{
string[] roles = { "Admin", "User", "Business" };
if(roles.Contains(roleName))
return true;
else
return false;
}
public override void CreateRole(string roleName)
{
Role newRole = new Role();
newRole.Name = roleName;
roleRepository.Add(newRole);
roleRepository.SaveChanges();
}
public override bool IsUserInRole(string userName, string roleName)
{
MyUser user = userRepository.Get(u => u.Username == userName).FirstOrDefault();
Role role = roleRepository.Get(r => r.Name == roleName).FirstOrDefault();
if (user.RoleID == role.RoleID)
return true;
else
return false;
}
}
}
I have been unable to find a way to override the
User.IsInRole(string roleName)
What else must I do so that When I use:
[Authorize(Roles = "Admin")]
It will be based on the role provider that I have set up and not the asp default.
My user class is now as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
using System.Collections;
using System.Security.Principal;
namespace Project.Data
{
public class MyUser : IPrincipal
{
[Key]
public int UserID { get; set; }
[StringLength(128)]
public string Username { get; set; }
.....other properties
public IIdentity Identity { get; set; }
public bool IsInRole(string role)
{
if (this.Role.Name == role)
{
return true;
}
return false;
}
public IIdentity Identity
{
get { throw new NotImplementedException(); }
}
}
}
My stack trace seems to be following over at:
System.Web.Security.RolePrincipal.IsInRole(String role)
So I have tried to implement a custom RolePrincipal in the same manner I set the custom Provider any ideas how I can do this? Not sure what constructor params it takes. Here is my attempt:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Configuration.Provider;
using Project.Data;
using System.Web.Security;
using System.Security.Principal.IIdentity;
namespace Project.Principal
{
public class MyPrincipal : System.Web.Security.RolePrincipal
{
private MyContext dbcontext = new MyContext(System.Configuration.ConfigurationManager.ConnectionStrings["MyContext"].ConnectionString);
private Repository<MyUser> userRepository;
private Repository<Role> roleRepository;
public MyPrincipal()
{
this.userRepository = new Repository<MyUser>(dbcontext);
this.roleRepository = new Repository<Role>(dbcontext);
}
public override bool IsInRole(string role)
{
//code to be added
return true;
}
}
}
You just need to override method GetRolesForUser in your custom role provider, instead of the more logical IsUserInRole, because that is what is called by the default implementation that does some unwanted caching.
To fix this, you need to do 4 updates to your application.
You override IsInRole in your IPrincipal class, mine in EF looks like this:
Then once you add the appropriate sections to your webconfig for both RoleProvider and MembershipProvider you should be good for Authorize attribute.
UPDATE in response to your comments
web Config should look like:
In the provider, is the User your
IPrincipal
?User should have and
IIdentity
in MyUser.cs:
I don't have much additional advice to help troubleshoot from your comments.
UPDATE
Some examples I have been through and found helpful when setting mine up: http://www.brianlegg.com/post/2011/05/09/Implementing-your-own-RoleProvider-and-MembershipProvider-in-MVC-3.aspx
http://www.mattwrock.com/post/2009/10/14/Implementing-custom-MembershipProvider-and-Role-Provider-for-Authinticating-ASPNET-MVC-Applications.aspx
http://blogs.msdn.com/b/rickandy/archive/2012/03/23/securing-your-asp-net-mvc-4-app-and-the-new-allowanonymous-attribute.aspx?Redirected=true
I read many other articles and SO posts on my first run through, but these were things I bothered to bookmark. I took a roles/rights approach to authorization, which is why one of them is geared that way.