MembershipProvider has methods
public abstract MembershipUser GetUser(
Object providerUserKey,
bool userIsOnline
)
to look up users by their unique identifier. This is useful if you want to have you own database and associate some objects of yours to certain memberships.
Can you do the same with RoleProvider ? There doesn't seem to be any methods to map roles to their unique identifier or vice versa.
As a side note is it a good idea to just add your own tables to the asp.net sql database or is it better to have a separate database for your own objects and have foreign keys into the asp.net sql membership table.
There is no way within the API to return a role from an ID - you can get all roles via
Roles.GetAllRoles();
Or you can get all roles for a user by
Roles.GetRolesForUser(userName);
But not a single role.
I would guess the reason for this is that roles on there own are probably not that useful (at least as far as Microsoft are concerned).
Of course roles are just a table within the database so you can easily add this functionality yourself with some straight SQL - it will just take a little more work.
In terms of additional data - I normally create my own tables within the same database with foreign keys as you have suggested above. Although if you have not heard of Profile Provider (http://msdn.microsoft.com/en-us/library/0580x1f5.aspx) you may want to look into that as well.
There's no such thing as an "asp.net sql database". There's simply the default database that asp.net creates for you if you haven't specified one. There is no reason to use this default database seperately from your regular database. This is why it has a connection string.
The whole point of membership is that it's flexible, to use as you see fit.
On a login page, the Page.User variable is still set to anonymous. If you'd like to verify roles before login, you can construct your own GenerpicPrincial like:
var principal = new GenericPrincipal(
new GenericIdentity(username),
Roles.GetRolesForUser(username));
Related
I have a project that is not released yet I will not be soon but I moved it from mvc3 to mvc4 a few days ago and while reading I saw this new security provider SimpleMembership.
The way I implement security now is by using MembershipProvider and FormsAuthentication:
I have implemented ICustomPrincipal
I have implemented CustomPrincipalSerializeModel
I have implemented IPrincipal
To register user I use:
MembershipCreateStatus status;
Guid g = Guid.NewGuid();
Membership.CreateUser(model.User.Email.Trim(), model.Password.Trim(), model.User.Email.Trim(), null, null, true, g, out status);
if (status == MembershipCreateStatus.Success)
...
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
1,
tUser.Email,
DateTime.Now,
DateTime.Now.AddDays(60),
true,
userData);
string encTicket = FormsAuthentication.Encrypt(authTicket);
HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
Response.Cookies.Add(faCookie);
...
But as I saw SimpleMembership looks much cleaner and I want to move project to it
but I have some questions about it:
1) I use stored procedures for all database actions I don't use EF at all. If I use SimpleMembership is it possible to use it without EF?
2) Do I need to build custom SimpleMembership for real world application?
3) I saw that it seeds database Create tables. I have my tables Users, Profiles, Roles and UsersInRoles can I apply it to my custom schema?
4) If I want to call WebSecurity.CreateAccount(...) and I want to call some my custom method from domain project that is responsible to call stored procedure that create user do I have to make it custom and if I have to do that is there some resource that explain how to make it custom for users and roles?
To understand SimpleMembership and how it has evolved from, and depends on, the previous Membership implementation, I recommmend reading the original reference "Using SimpleMembership With ASP.NET WebPages (Matthew Osborn)", and my more detailed answer to "What is MVC4 security all about?" to understand it better. To summarise those references:
SimpleMembership
is a term that covers both the SimpleMembershipProvider and the SimpleRoleProvider
is a storage and functionality provider that is used with Forms Authentication
works within ASP.NET Forms and ASP.NET MVC websites, and can also be used within ASP.NET Web API and SignalR, to provide a unified authentication and authorisation model
SimpleMembershipProvider
adds new features to the original MembershipProvider through the ExtendedMembershipProvider abstract base class, such as integration with OAuth providers out of the box
creates 4 default tables which you don't/shouldn't interact with (webpages_Membership, webpages_OAuthMembership, webpages_Roles, webpages_UsersInRoles) and one (UserProfile) which is yours to structure as you wish
works with the WebSecurity helper class to add new functionality
Moves from the "user profile" stored in a single xml field in the original Membership, to a more manageable property-per-column in the new UserProfile table (which is fully customisable using EF)
To answer your specific questions:
1) I use stored procedures for all database actions I don't use EF at all. If I use SimpleMembership is it possible to use it without EF?
You would not generally interact directly with the tables prefixed with webpages_ as there are API level functions in Membership, WebSecurity etc. to do all the business functions you require. However there is nothing to stop you interacting with UserProfile through stored procedures, and if you didn't want to take advantage of the APIs, you could even interact with the webpages_ tables through sprocs as well (but you would just be duplicating all the benefits of SimpleMembership if you did).
2) Do I need to build custom SimpleMembership for real world application?
That very much depends on what you want to do, but as yet I have not had to do this for any real world applications. I have built on and added to the existing APIs, but not replaced them.
3) I saw that it seeds database Create tables. I have my tables Users, Profiles, Roles and UsersInRoles can I apply it to my custom schema?
If you were migrating to SimpleMembership you would have to port the data in these to the tables webpages_Membership, webpages_OAuthMembership, webpages_Roles, webpages_UsersInRoles and UserProfile. However, note that UserProfile can be called anything you want, you don't have to call it UserProfile.
4) If I want to call WebSecurity.CreateAccount(...) and I want to call some my custom method from domain project that is responsible to call stored procedure that create user do I have to make it custom and if I have to do that is there some resource that explain how to make it custom for users and roles?
Its a little hard to understand your requirement, however WebSecurity.CreateAccount does the following:
Creates a record in webpages_Membership and
optionally adds properties to UserProfile if you use WebSecurity.CreateUserAndAccount
If you wanted to do other actions across your database you would then need to call that after your call to WebSecurity.CreateAccount. You can make this transactional by using TransactionScope
If however you wanted to wrap this all in a single call to WebSecurity.CreateAccount and make it call your own domain methods and stored procedures you will have to create your own provider by inheriting from SimpleMembershipProvider (or from ExtendedMembershipProvider). When WebSecurity.CreateAccount then calls ExtendedMembershipProvider.CreateAccount it will defer to your custom logic
Summary
So would I migrate? The benefits of SimpleMembership are meant to be:
UserProfile: property-per-column storage of user data that plays well with EF or any other db development method
Integration with OAuth, allowing you to use Google, Facebook etc. authentication with very little effort
High level business function APIs in the form of WebSecurity, and continued support of existing features with Membership
Continued support for Roles that works with the Authorize attribute
Integration with EF so that you can use UserProfile along with your own tables
Integration with standard Forms Authentication for ASP.NET Forms and MVC, and also with SignalR and Web API.
If those help you out, then migrate, otherwise spend your dev time on new features for your application.
If you do decide to migrate, then "Migrating Legacy Apps to the New SimpleMembership Provider (Paul Brown)" is useful, which is summarised as:
Modify UserProfile to have a field per property for your old user profile properties that were stored in xml
Migrate your data from the aspnet_ tables to the webpages_ tables
The first time each user logs in again, update their stored password to use the new hash model instead of the old Membership one (see the footnote to my answer here for how to do this)
#Andy Brown makes a lot of good points. I would note to anyone who lands on this that Simplemembership is basically dead and was short lived with ASP.Net Identity coming out shortly after it and is what is used in all new projects. Such a short lived membership product.
When you create a new ASP.NET internet application, you get the built in membership tables and controllers etc. There are 5 tables created:
UserProfile
webpages_Membership
webpages_OAuthMembership
webpages_Roles
webpages_UsersInRoles
I understand the basic concept of how all these work but I have a question on why is a UserProfile create along with the webpages_Membership? Can't these 2 tables practically be combined together? If that's not how it works, can you explain to me why the 2 files were created.
No, they cannot be combined, because a user profile has nothing to do with membership. Membership is about your user id, password, and authentication. User Profile is about things like name, address, etc..
It's designed this way so that you can extend the user profile to include whatever information you want. While the Membership tables do not change, because those are "hard wired" into the provider.
This is a weird way to state the question, but this is what I'm trying to achieve.
This is what I'm doing
Connect to a MySQL Db(complete)
authenticate(complete)
select all the roles that I have specified in mySQL (complete)
store those roles somehow so I can display controls and links based on their role membership.
I just got this figured out to handle the mySQL part in web.config
system.web
membership defaultProvider="MySQLMembershipProvider" /
roleManager enabled="true" defaultProvider="MySQLRoleProvider" /
/system.web
I'm using this as code
MySqlDataReader dr2 = cmd2.ExecuteReader();
while (dr2.Read())
{
string roleName = dr2["role"].ToString();
//error here -> Roles.AddUserToRole(userID, roleName);
}
Access denied for user ''#'localhost' (using password: NO)
Is Roles.AddUserToRole really what i'm looking for to satisfy my needs. I think I need to store the user roles in the sessio don't I? I
Is Roles.AddUserToRole really what i'm looking for to satisfy my needs. I think I need to store the user roles in the sessio don't I?
NO! Adding user to roles means the provider will link the user to the role. As you already have the user linked, this is a worthless direction.
store those roles somehow so I can display controls and links based on their role membership
Why do you need to do this? At the page level, you can set up ASP.NET security with trimmings so you can automagically exclude pages from the user's view if they are not in the correct role(s). As far as sections/controls/etc, you can check to see if a user IS in a role and then determine whether or not to display it. If you use sections, a lot of this can be done declaratively rather than programmatically.
The one caveat is what your membership provider supports. The "out of the box" providers (Access and SQL Server) support security trimmings and declarative syntax for exclusions of sections of a page, etc. If the MySQL provider full implements all of the methods, you should be fine using it, as well. If you create a custom provider, there are certain parts YOU have to implement to get things to work.
The short story is once you grab a membershipUser (authenticate the person), you will have access to whether the person is in role or not. This is all part of the standard implementation of a membership provider in .NET. As long as the provider you are using for MySQL covers all of the same methods, you can do a quick google search and find tons of sites showing how to show/hide bits based on roles.
I am going to use forms authentication but I want to be able to link the asp.net users to some tables in the db for example
If I have a class and students (as roles) I'll have a class students table.
I'm planning to put in a Users table containing a simple int userid and ASP.NET username in there and put userid wherever I want to link the users.
Does that sound good? any other options of modeling this? it does sound a bit convoluted?
Basically, the ASP.NET membership service creates a GUID per User, so if you need to have a foreign key of the user in a table, then this is what you should use. As such, you will not need the mapping table of a username to a userid as you already have a unique identifier per user (the aforementioned GUID)
If your looking to extend the amount of information one can store against a user, then this link has all the details regarding that.
If you're going to use ASP.NET membership, you should create the users with the ASP.Net Membership classes and database tables. This will create a user in the dbo.aspnet_Membership with the appropriate roles set for that user, upon successful insertion into this table, you can get the UserId from the dbo.aspnet_Membership table.
In YOUR Users table create a table with an int(auto-incrementing) ID, and also create a membershipID field in your table(rather than username) of type uniqueidentifier called say, membershipID. This is where you would store the value from the aspnet_Membership table to link the two together. You should also put a foreign key relationship on your membershipID field for referential integrity.
EDIT: Just to clarify with the other posts, id is of type GUID in your ASP.NET code, and of type uniqueidentifier in your SQLServer database.
We did this for a system where we retro-fitted forms authentication into a system using another authentication system. We added a column to our existing user account table. We added a GUID column, since this is what the aspnet_xxxx tables use, and filled it with the GUID from the aspnet tables. We then wrapped creation of our entry in our table into a transaction dependant upon the success of account creation using the asp.net membership calls. It's very important to make sure you sync the tables together with a transaction or something to make you don't have entries in one system and not in the other.
I'm not 100% sure, but I think that usernames can change so you shouldn't use that to link your systems. Use the GUID.
Hope this helps
I know how to create users and assign them to roles etc, but when I tried to dig a bit deeper into how roles and membership tables are able to establish a relationship between each other, I got totally lost ( BTW – I do know how foreign/primary keys work ;) )
BTW - I've created tables in databases using aspnet_sqlreg wizard
Q1 - Both SqlRolesProvider and SqlMemebershipProvider have a property ApplicationName. I thought that in order for the two providers to be able to create association between their users and roles, they would both have to use same value for ApplicationName property. But that doesn’t seem to be the case.
A) Anyways, I assume that SqlRolesProvider.ApplicationName property is only used to distinguish between table entries belonging to different role providers, but they don’t use that property in order to associate their roles only with membership providers with the same ApplicationName value?!
B) But wouldn’t it be most practical if roles providers could only be associated with membership providers with the same ApplicationName value ( thus where SqlRolesProvider.ApplicationName == SqlMemebershipProvider.ApplicationName)?!
Q2 - I was also curios whether roles and users could be associated if roles provider was connected to DB1, while membership provider was connected to DB2. Somehow I was still able to assign users to different roles, even though roles were defined in different database.
A) But why is that? Namely, if SqlRolesProvider.ApplicationName = “rolesP” ( ApplicationID=10 ) and SqlMembershipProvider.ApplicationName = “membership” ( ApplicationID=100 ), then in order for the table in DB1 to have relationship with table in DB2, the two would have to reference each other via ApplicationName entry ( actually via ApplicationID), which would act as foreign/primary key.
But the thing is, none of the foreign key fields in DB1’s tables holds a value equal to SqlMembershipProvider.ApplicationID = 100, which would suggests that there is no relationship established between tables in DB1 and DB2 ( I know that is not the case, since I’m able to assign users to roles ). So what am I missing?
thanx
EDIT:
Uh, don't know if anybody will still be reading this, but I did some more digging and got even more confused:
If both roles (with applicationName=R1 and applicationID=10)and membership provider(with applicationName=M1 and with ApplicationID=100) are in same DB, then creating a new user causes aspnet_Users table two create two entries for same user name– one with ApplicationID=10 and other with ApplicationID=100. As far as I know, when new user is created, only one field ( with ApplicationID=100 )should be added to aspnet_Users. Uh?!
Have you looked at the aspnet_UsersInRoles Table. This is the table that links the user to the role. The RoleProvider is designed to be separate from the MembershipProvider so that you can have them in separate DB's. Additionally it allows for you to set up roles for one application name and re-use those roles in two separate applications that each have a different application name for the membership provider. Don't get stuck in the mentality that you have to have the same application name for both providers or that your application name needs to match the running application. You don't need to have any name at all if you don't want to. I hope that this helps.
I had a hard time following what you were saying...
Anyway... you seem to be looking at the database too much. Have you configured the web.config for your membership providers and were you able to query "Membership" using C# and NOT SQL queries?