问题
I've been reading tons of articles and forums but I still can't figure it out... I'm building an internet application using Visual Studio Express 2012 for Web, with MVC4+Razor+Entity Framework CodeFirst.
As far as I understand, managing users and roles in MVC4 with SimpleMembership is more straightforward than it was in previous versions and should be fairly simple.
In my application, I need to authorize only certain groups of users (e.g., only admins can access certain pages). I understand that's made by passing a parameter to the [Authorize] annotation: [Authorize(Roles="Admins")] But how do I create those roles and how do I add users to them?
In order to require authentication I added the annotation [Authorize] (with no parameters) on top of a controller method and it worked without having made any extra configurations or adding anything else. Also, when I take a look at the database that was automatically created, I see a table named webpages_UsersInRoles, with columns UserId and RoleId. All of this makes me think this has to be a pretty simple task since all seems set up and ready to be used, but I just can't figure out how ;)
What I've tried so far (and it didn't work) was this: I have a "DataContextDbInitializer" class that inherits from DropCreateDatabaseIfModelChanges. The Seed method is overriden inside that class, and I added this (I had to import System.Web.Security):
Membership.CreateUser("user1", "123456");
Roles.CreateRole("Admins");
Roles.AddUserToRole("user1", "Admins");
I also inserted this tag in the tag of the Web.config file:
<roleManager
enabled="true"
cacheRolesInCookie="true" >
</roleManager>
To try it out I added [Authorize(Roles="Admins")] on top of an action method in a controller, and then logged in as "admin" and tried to access that method, but no luck :(
I don't know what else I'm missing... I'd be really happy if anyone could guide me through this, since it's driving me insane :P
Thanks!
回答1:
My guess is that your Seed method is not getting called. Verify this is getting called by putting a break point in the method and running it in the debugger. Unless you made some other changes to your application the EF migration is not being used. By default the database is initialized with the InitializeSimpleMembershipAttribute. You will see that this attribute is added to the Account Controller as shown in the following code.
[Authorize]
[InitializeSimpleMembership]
public class AccountController : Controller
{
....
}
This way it is only invoked when the AccountController is accessed. You will find the definition in Filters\InitializeSimpleMembershipAttribute.cs. Here is a code snippet from this class that may be clue to why it not being called.
// Create the SimpleMembership database without Entity Framework migration schema
((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
A lot of the code in InitializeSimpleMembershipAttribute is put in place to handle the scenario where Forms Authentication is not used for the MVC application. If you will always be using Forms Authentication you can eliminate this code and initialize the database yourself. Just remove this attribute from the AccountController and put your own initialization code in the Global.asax Application_Start method. You would add something like this to the Application_Start method
Database.SetInitializer<UsersContext>(new MyDBInitializer());
The Seed method look like this
WebSecurity.InitializeDatabaseConnection("DefaultConnection",
"UserProfile", "UserId", "UserName", autoCreateTables: true);
var roles = (SimpleRoleProvider)Roles.Provider;
var membership = (SimpleMembershipProvider)Membership.Provider;
if (!roles.RoleExists("Admin"))
{
roles.CreateRole("Admin");
}
if (membership.GetUser("user1", false) == null)
{
membership.CreateUserAndAccount("user1", "123456");
}
if (!roles.GetRolesForUser("user1").Contains("Admin"))
{
roles.AddUsersToRoles(new[] { "user1" }, new[] { "Admin" });
}
Note that you need to initialize the web matrix security database in your Seed method by calling the WebSecurity.InitializeDatabaseConnection method.
You can find more detailed information on seeding SimpleMembership in this blog post, which includes the complete source code for the example project.
回答2:
Finally, I managed to make the whole thing work!
My seed method now looks like this:
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
if (!Roles.RoleExists("Admins"))
{
Roles.CreateRole("Admins");
}
if (!WebSecurity.UserExists("admin"))
{
WebSecurity.CreateUserAndAccount("admin", "123456");
}
if (!Roles.GetRolesForUser("admin").Contains("Admins"))
{
Roles.AddUsersToRoles(new[] { "admin" }, new[] { "Admins" });
}
base.Seed(context);
My App_Start in Global.asax looks like this:
Database.SetInitializer(new DataContextDbInitializer());
DataContext c = new DataContext();
c.Database.Initialize(true);
I'm not sure if this is actually doing something, but I have this inside the the system.web tag in Web.config:
<roleManager enabled="true" cacheRolesInCookie="true" />
I also removed [InitializeSimpleMembership] from AccountController, and the UsersContext class in AccountModels. I moved this bit to my own context class:
public DbSet<UserProfile> UserProfiles { get; set; }
Then, to test if everything works, I use the [Authorize(Roles = "Admins")] annotation on top of the About() method in the HomeController. If things are working as expected, this should force me to log in as admin/123456 in order to be able to see the "About" page, controlled by HomeController/About. Which does ;)
来源:https://stackoverflow.com/questions/14527152/how-exactly-do-i-use-roles-in-asp-net-mvc-4