Avoid Multiple calls to GetUser when using ASP.NET Membership - asp.net

I am using ASP.NET Membership in an ASP.NET MVC 3 Web application project.
I have installed the ASP.NET Membership tables using Aspnet_regsql.exe and now my main userTable has a foriegn key called "userID" which points to the "UserId" of aspnet_Users.
This "userTable" is connected to many tables. So for every operation now I require the "UserId" from aspnet_User using the username with which the user has logged in.
For this I use
MembershipUser user = Membership.Provider.GetUser(username, true);
now for each and every operation I have to make this call and get user.ProviderUserKey to continue with my other operations.
I am thinking there has to be a better way to do this. Is any any built in way to do this ?

The ASP.NET Membership Provider isn't intended to provide the ProviderUserKey... perhaps you could use the username instead? You can always easily access that through Context.User.Identity.Name.

I always use:
Guid userId = (Guid)Membership.GetUser().ProviderUserKey;

You get the user information once and put it in forms authentication cookie with user data encrypted.
For subsequent calls you use Context.Identity for the user information

You can keep the relevant information around in the cache, for example in a Dictionary<string, Guid> where the key is the user name (which you can lookup using HttpContext.Current.User.Identity.Name or Thread.CurrentPrincipal.Identity.Name), and the ProviderUserKey is the value.
Build this dictionary either on-demand or initialize it once, and put it in the ASP.NET Cache, Session or Application (of course watch our for serialization and concurrency issues).

Related

Another ASP.NET custom membership/role provider

ASP.NET 4.5 / C# / SQL 2012
I already have a well defined database with a users table and a roles/permissions column. The column contains a delimited list of roles. I was hoping to use ASP.NET's built in features on the back-end so I can be lazy and use things like the and filter by role. I'd like to read my roles from the database and tell ASP these are the roles my user is in. Custom...but hopefully simple. Here is what I have so far:
//create an identity
GenericIdentity objIdentity = new GenericIdentity("Matt"); //this would actually be the username/email of the newly authenticated user
//get roles for user
string[] strRoles = { "ADW", "USR" }; //this will get read from the database on authentication
//add identity and roles to a principal
GenericPrincipal objPrincipal = new GenericPrincipal(objIdentity, strRoles);
//add to current user
HttpContext.Current.User = objPrincipal;
//add the principal to the current context of the current thread
Thread.CurrentPrincipal = objPrincipal; //not sure what this does, doesn't affect my results/tests
If I execute the code above and then run the following:
Response.Write(User.IsInRole("ADW"));
Response.Write(User.IsInRole("xxx"));
I get a True/False as expected. However, this doesn't persist to the next page. I did a fair amount of reading on custom membership/role providers, but I can't find this specific use case. Most talk about setting up a DB specifically for this task. I also saw mention of the newer Simple Membership, but couldn't get any love from that end either. I'm hoping there is a solution that involves what I'm already doing. I'd love to execute this code when the user authenticates, but be able to reference this user in other pages. I could always call to the database for every page. I'm assuming that would suck, and that's not what the built in provider does.
Thanks all.
You are approaching it from the wrong side. You don't have to create identity and principal manually, assuming you are not creating a custom authentication module.
In any other case, you only choose the persistence mechanism and the corresponding authentication module sets the identity/principal according to the persistence.
A commonly used persistence mechanism is Forms Authentication, where you issue forms cookies. The forms authentication module makes sure the identity/principal is set early in the pipeline and takes the cookie as the source of information.
If you want to replace the cookie by your custom cookie (in other words - replace forms authentication with your own) - you have to think of a way to persist the security info, to the cookie for example.
Note, however, that this is probably not necessary. The very same forms authentication can be used with any custom membership and role providers. This is because these two have different responsibilities - membersip provider is for actual authentication whereas forms authentication module is for persisting the information for consecutive requests.
Edit: to add a role for a user so that it is persisted in the user database:
Roles.AddUsersToRoles( ... );
But first, you'd have to create users in the user database:
Membership.CreateUser( ... );
Note that Roles and Membership are facades for actual role and membership providers. While default providers use the membership database, you can easily create custom providers that persist the information anywhere at the server side.

acessing username in web api controller when database table stores user as integer

Inside some web api controllers, I would like to access the User as indicated in this answer: https://stackoverflow.com/a/12705062/538962
sample code from answer...
[Authorize]
public List<Product> GetProductsFromId()
{
string username = User.Identity.Name;
return _productService.GetProductsFromUsername(username);
}
The asp_net membership tables in my scenario are on a different database server than then the database server the application runs on. The database for the application has its own Users table with an IDENTITY column as the Primary Key on the Users table, and then other tables that include a CreatedByUserID and UpdatedByUserID columns are integers based off the IDENTITY column in the users table.
The issue is that if CRUD type operations depend on the user being updated in tables as an INTEGER, just accessing the username alone is not sufficient; we still have to get to that username's corresponding UserID.
This could be done with another join to the Users table, but this seems a bit kludgy. What would be the best way to go about handling this issue?
From the perspective of ASP.NET Web API, using membership provider and the out-of-box FormsAuthentication is already kludgy, so why not the join? :) Anyways, assuming your web API is consumed by only the web clients and FA is cool, you can use the UserData of the FA ticket to put in the user ID. That way, you don't need to get the ID by hitting your DB every time. But you will need to create the ticket yourself and not let the default out-of-box implementation do that for you. Then, in the PostAuthenticateRequest event, you can read the user ID from the ticket and set it in the identity. Of course, you need to create your own custom identity for this with an ID property or if you are on .NET 4.5, you can use FormsIdentity itself but you can use the NameIdentifier claim to store the ID, perhaps. Check this out - ASP.NET MVC - Set custom IIdentity or IPrincipal.

add user and assign role in aspnet membership through sql servers SP

Tech - asp.net 3.5, Sql server 2005
I have integrate aspnet membership for my webapplication.
I am adding some users (member) from importing excel file.
So how can I add that user and role of that user in aspnet membership tables?
NOTE - I have SP which is used to add member in DB from uploaded excel file, I have wrote insert trriger on membertable.
Do not insert DB records manually. Use .NET's Membership Provider's stored procedures to do that, for example aspnet_Membership_CreateUser and aspnet_Roles_CreateRole.
But better off, use .NET's classes/methods to do that. They encapsulate the whole mechanism for you:
Membership Provider
Role Provider
First you create a user, then you (optionally) attach role(s) to.
UPDATE December 2015
Folks keep reading this. It's important to know that for a few years now, there is a totally different paradigm, ASP.NET Identity. please use it instead of the old Membership Provider.
Abhi you should use
//to create a user
MembershipUser newUser = Membership.CreateUser(UserName, Password, Email);
//to attach created user some role
Roles.AddUserToRole(newUser.UserName, role);
Update
For that you can for for membership stored procedure aspnet_Membership_CreateUser to create a user or you can create one for you to insert data into user and userinroles table.
I would encourage you to refer link
You can simply do INSERT in the AspNetUsers table with empty PasswordHash and SecurityStamp. Then we have a "forgot password" flow that establishes credentials using ASP.NET Membership.

How can I check for authorization when using forms authentication?

I am developing an ASP.NET website. I am planning to use Forms authentication in order to guarantee authentication/authorization, but I am facing two problems regarding the authorization:
I know how to set in the web config that the authenticated users are allowed to visit a webpage (say myPage.aspx). But I do not know how to define that UserA is able to access myPage to retrieve his information, not UserB's information.
I was thinking about generating a token when the user authenticates, so I am able to check to whom this token belongs to and verify if this information is available to him.
What do you think about this approach? Does the Form Authentication generates a token like that? (I couldn't find any mention about it in my research). If not, could I adapt the Form authentication mechanisms in order to generate or would I need to write everything on my own?
I would like to access webservices, and these should only return information if the user is logged. For this reason, I would like to use the same token explained above. What do you think about it? Is it a good approach?
I am asking this because I have no experience on designing authentication/authorization mechanisms, any help/hint would be appreciated.
Regarding question one, after forms authentication occurs in an ASP.Net web forms app, the user's identity is exposed as a FormsIdentity object in the Page.User.Identity property. This object has a Name property which contains the username that a user use to log into your site. You can use this value to restrict what a user can access. For example, let's say you have a table in your database with user information containing the following fields:
userId int
userName varchar(25)
...more fields containing user information...
You can restrict a user to only access information from the row in this table in which the userName equals the Page.User.Identity.Name property, either directly if you are using direct ADO.Net or via your query to your ORM-mapped (i.e. nHibernate or EF) domain object.
Regarding question two, the FormsIdentity object exposed by Page.User.Identity has a boolean "IsAuthenticated" property. You can use this to restrict access to your web service as follows:
if(Page.User.Identity.IsAuthenticated)
{
//Call your web service in a secure manner
}

Asp.net membership

If I want to do an admin function like delete a user on the asp.net membership stuff that ships with the asp.net mvc sample.
I tried looking through the tables and realized that there was multiple tables that had rows added. I assume there must be a simpler way.
In your Membership provider there is a method:
public bool DeleteUser(string username, bool deleteAllRelatedData)
If this is the standard asp.net membership provider that method runs a stored proc that cleans the user from your DB.
Here is some more examples:
https://web.archive.org/web/20210304121422/https://www.4guysfromrolla.com/articles/091207-1.aspx
Use the Membership API's.
To delete a user, use the Membership.DeleteUser method
Membership.DeleteUser(User.Identity.Name, true);
Don't delete direct from the database, go through the membership provider and call the Membership.DeleteUser method.
The Membership Provider base class has the methods you need. For example to delete a user you use the DeleteUser method. What you do NOT do is directly access the SQL database
You can also use the ASP.NET Configuration Tool.
http://msdn.microsoft.com/en-us/library/ms998347.aspx - Step 3 shows how to add users. The same principle applies for deleting them. You can also mark them as inactive instead of deleting them. I usually mark them as inactive to preserve my database relationships.

Resources