In my UserController.Login
action, I am trying to AddUserToRole()
for an authenticated user, with the value of one of the user entity's MembershipType.MembershipName
navigation property:
Roles.AddUserToRole(thisUser.UserName, thisUser.MembershipType.MembershipName);
I'm not using the bloated auto-generated membership types and simply want to add the text value to the user's role - not a range of roles. User --> one role.
In trying to figure this out, I defined a custom role provider in web.config:
<roleManager enabled="true" defaultProvider="CustomRoleProvider">
<providers>
<clear/>
<add name="CustomRoleProvider"
type="MyWebsite.CustomRoleProvider,
CustomMembershipEF, Version=1.0.0.0, Culture=neutral"
connectionStringName="MyDbContext"
enablePasswordRetrieval="false" enablePasswordReset="true"
requiresQuestionAndAnswer="false" writeExceptionsToEventLog="false" />
</providers>
</roleManager>
So calling Roles.AddUserToRole() calls the method in my custom provider, but I'm not sure what to do in that method.
Earlier I simply added enabled="true"
to the rolemanager
section in web.config, but was getting the following error:
Unable to find the requested .Net Framework Data Provider. It may not be installed.
Here's my custom role provider (although I don't know why I should need this, as I just want to add the role name):
public class CustomRoleProvider : RoleProvider
{
public override bool IsUserInRole(string username, string roleName)
{
using (var db = new MyApp.DAL.MyAppDbContext())
{
var user = db.Users.SingleOrDefault(u => u.UserName == username);
if (user == null)
return false;
if (user.MembershipType != null && user.MembershipType.MembershipName == roleName)
{
return true;
}
}
return false;
}
public override string[] GetRolesForUser(string username)
{
using (var db = new MyApp.DAL.MyAppDbContext())
{
var user = db.Users.SingleOrDefault(u => u.UserName == username);
if (user == null)
return new string[] { };
return db.MembershipTypes == null ? new string[] { } :
db.MembershipTypes.Select(u => u.MembershipName).ToArray();
}
}
// -- Snip --
public override string[] GetAllRoles()
{
using (var db = new MyApp.DAL.MyAppDbContext())
{
return db.MembershipTypes.Select(r => r.MembershipName).ToArray();
}
}
// -- Snip --
public override void AddUsersToRoles(string[] usernames, string[] roleNames)
{
throw new NotImplementedException();
}
I'm thinking this should be quite simple to accomplish - simply set the user's role name... assistance appreciated.
-- Update --
I commented out the content of the custom AddUserToRole()
method, and the user is able to login. However, in calling an action method, the role check wasn't performed - ie. should have failed since the role name doesn't actually exist:
[HttpGet]
[AllowAnonymous]
[Authorize(Roles="WaitConfirmationxxx")]
public ActionResult WaitConfirmation()
{
I also noticed that IsInRole()
called the custom GetRolesForUser()
method which does a db call in it. Not exactly optimal, and wondering if this is actually how it should be?
if(User.IsInRole("WaitConfirmation"))
{
// email address has not yet been confirmed
return RedirectToAction("WaitConfirmation", "User");
}
-- Update --
My mistake here was thinking that I needed to use Roles.AddUserToRole()
(unless someone comments otherwise).
I also added the cacheRolesInCookie
parameter in the roleManager
definition in the web.config:
<roleManager enabled="true" defaultProvider="CustomRoleProvider" cacheRolesInCookie="true">
So now when I call if(User.IsInRole("WaitConfirmation"))
, my custom GetRolesForUser(string username)
is called.
The problem now is that none of the Authorization
attributes work. Suggestions?
You need to remove the [AllowAnonymous]
attribute, change it to this:
[HttpGet]
[Authorize(Roles="WaitConfirmationxxx")]
public ActionResult WaitConfirmation()
{
If your RoleProvider is configured correctly, it should kick into this method when it tries to authorise from the attribute on the above method.
public override string[] GetRolesForUser(string username)
{