Implementing Custom Membership Provider Membership User Issues - asp.net

I am trying to implement a custom membership provider and want to change the GetUser method. The problem is that GetUser returns MembershipUser and I want to return MyMembershipUser which has two additional properties FirstName and LastName. I can create a new method in my membership provider which returns MyMembershipUser but then I think it won't make any sense.
How would I go about doing this?

That would defeat the purpose of the Membership classes. Do something like this if you need to access other properties:
var user = Membership.GetUser(userName, true) as MyMembershipUser;
Really you should have a separate Profile class that handles things that MembershipUser does not provide.
var profile = Profile.GetProfile(Membership.GetUser(userName, true));

You should go for Profile Provider.
check this link, you have either SqlStoredProcedureProfileProvider and SqlTableProfileProvider, this way you have ability to store Profile data “in the clear” in the database, letting you query the db whenever u want.
"you can implement whatever business logic you need in the stored procedures to map the Profile data to your own database schema and database logic."

If MembershipUser is the base class of MyMembershipUser then you can return instances of MyMembershipUser even though the return type of GetUser() is MembershipUser and then, if necessary, cast them back to MyMembershipUser (but do you really need to do that?)
BTW, this is an example of polymorphism.

Related

Custom fields in ASP.Net Login/Register?

I have to edit the Login/Registration that ASP provides to include a custom dropdown ("BranchID") menu that saves to the database so each user has its own Branch. I am using ASP Membership system, and of course it saves to the ASPNETMDF database it creates. Googling has net me some results but I am quite confused. I know there are "User Profiles", and I I can save this Profile data, but what I am not quite sure is if its a temporary measure or if it does record to the database.
I could make my own custom membership system, use the built it and adapt it or use the user profiles. What is the best course of action? I'd vastly prefer to adapt/edit the built in Membership system and add the data I require to it but I still don't haven't a clear answer to what I should do or what's best.
You have two choices:
Create a CustomMembershipProvider , and if you need to a CustomRoleProvider, you can do this by implementing .NET's MembershipProvider. Sample: http://www.codeproject.com/Articles/165159/Custom-Membership-Providers
Create a separate table that stores additional user information, i.e., "BranchID", and add a one-to-one relationship between your table and .NET's Membership
It's really up to you which one you choose.
MembershipProvider is pretty easy to extend. Assuming the branch is something they have to select to authenticate? You should be able to extend authenticate to do something like:
public class MyCustomMembershipProvider : MembershipProvider
{
/*
....
*/
public bool ValidateUser(string username, string password, string branch)
{
return (::ValidateUser(username, password) && MyCustomRoutine(username, branch));
}
}

Switch to SQL membership provider from AD membership provider runtime

In my asp.net application admin functionality, I am trying to combine AD authentication and form authorization for creating the users, roles and Assign users to roles etc. I have configured MembershipADProvider and AspNetSqlMembershipProvider in my web.config with MembershipADProvider as the default one. After user logs in using AD authentication, I need to switch/assign my membership object to use AspNetSqlMembershipProvider in order to get all the users from membership object (from dbo.aspnet_Users table). How do I switch the provider during run time? I have tried different approaches after searching for this issue and none of that seem to work for me so far.
Here are couple of approaches I tried:
1. foreach (MembershipProvider mp in Membership.Providers)
{
if (mp.Name == "MembershipADProvider")
{
Membership.Providers.Remove(MembershipADProvider");
MembershipUserCollection users = Membership.GetAllUsers();
ddlUsers.DataSource = users;
ddlUsers.DataBind();
break;
}
}
Membership.Providers.Remove(MembershipADProvider"); - doesn't work as it's not supported..
Also, tried to clear the Membership.Providers and then add only the type of AspNetSqlMembershipProvider which are also not supported.
I can't set Membership.Provider with value from
Membership.Providers["AspNetSqlMembershipProvider"] as Membership.Provider is a read only property.
I tried to swtich the connection string between 2 providers, which didn't swtich the provider, as both are different types of providers..if both were sqlserver providers this would have worked I believe.
Please let me know if anybody has successfully implemented or if at all this is a plausible approach. Thank You!
You would pass an explicit provider to your code, rather than taking a dependency on Memebership directly (which just wraps the one flagged as default in the config). There is no need to swap them in and out at runtime, think how this would affect thread safety.
So rather than saying Membership.GetAllUsers(); you would do something like (I don't have a compiler to hand):
public UserSerivce : IUserService
{
private MembershipProvider provider;
public UserService(MembershipProvider provider)
{
this.provider = provider;
}
public IEnumerable<MembershipUser> GetUsers()
{
return provider.GetAllUsers();
}
public void DoSomethingElseUseful()
{
...
}
}
And then to use it for a particular provider:
var service = new UserService(Membership.Providers["mySqlMembershipProvider"]);
var users = service.GetUsers();
Or if using AD specific code:
var service = new UserService(Membership.Providers["myADMembershipProvider"]);
var users = service.GetUsers();
Using DI in this way also helps keep code testable.
If all you need a list of users in the aspnet_Users table, just connect to your database with System.Data.SqlClient objects and query the table. There is no reason (that you mentioned) you need to use a membership provider to get that data.
Having said that, your membership/authentication scheme sounds like it may have some design issues, perhaps best tackled in a different question, but I think it might be useful to you if you sought comment on what you are trying to accomplish overall with the multiple membership providers.
Edit: I found some potentially useful posts on using multiple membership providers. It looks like the general idea is to implement custom code handling the Login.Authenticate event on your Login control, and use Membership.Providers["ProviderName"].ValidateUser to attempt authentication with each provider.
http://www.stevideter.com/2008/03/20/using-two-membership-providers-for-aspnet-logins/
http://forums.asp.net/p/1112089/1714276.aspx

How about keeping roles together with the name in user.identity.name | FormsAuth.SetAuthCookie(strUser + "|" + strUserRole)

Is it a good idea to keep the user's role together with his name, for example with setAuthCookie, do you:
formsAuthSrv.SetAuthCookie(strUser+strRole);
and you can do your own roles provider like this:
public class MyRoleProvider : RoleProvider
{
public override string[] GetRolesForUser(string username)
{
// get the roles from username and return it as an string[]
..
return new string[] { role };
}
}
and when you call user.identity.name you have to split it to get just the username
Is there a better alternative?
I would advise against it. IIdentity.Name is usually used to store a user identifier such as a user name or ID. Changing its use will mean standard code practices such as using HttpContext.User.Identity.Name will not work as expected and could be confusing when you or others are maintaining your code in the future.
As the IIdentity.Name is taken from the authentication ticket (by default) it would make more sense to store the role information in the UserData property of the authentication ticket.
You could then extract this information in your RoleProvider or create a custom IPrincipal for every request. That way User.Identity.Name and User.Identity.IsInRole will still work as expected.
This question contains more information about using the UserData property of the authentication ticket to store user roles.
This would be possible, but I don't think this is a good idea. For example, you would have to make absolutely sure the Username does not contain a | sign, for it will break your split.
I suggest creating a custom FormsAuthenticationTicket. One of the values in this ticket, besides the username, is userData. In this value you can store the roles of the user. With every request, you can read this cookie, and create a correct Identity with the roles.
Check here for some more info about this method: http://msdn.microsoft.com/en-us/library/aa289844%28VS.71%29.aspx
You wouldn't be able to do live user role updates with this, they would have to log out and in again to pick up new roles.

ASP.NET Provider with Different Types of Roles

I have different types of Roles to take into account when authorizing a user.
For example: John must have Position Manager and be part of the Office Supplies Department to order a new computer.
Problem with Roles is Roles.GetRolesForUser("John") can only return a string array.
Should I go with a custom roleProvider and custom roleManager?
or should I develop a custom ProfileManager to add methods like GetUsersWithProfileProperties()?
Any suggestion is welcome!
Thibaut
EDIT: the above example is simplified I could have a much as 4 types of roles which are 4 different collections.
EDIT: I found a very similar question
From what you write; I believe that everything you need is currently available out of the box:
// Return all Users in a Role
string[] users;
users = Roles.GetUsersInRole("RoleName");
// Return all Roles for a User
string[] roles;
roles = Roles.GetRolesForUser();
// Search through Membership store locating users with a role
MembershipUserCollection mu;
mu = Membership.GetAllUsers();
// Loop through all membership users looking for users in a role
foreach(MembershipUser m in mu){
if(Roles.IsUserInRole(m.UserName, "Role Name")){
// Do something
// We can even nest to x levels
if (Roles.IsUserInRole(m.UserName, "Another Role")){
// Do something else
}
}
}
Please clarify if I have misunderstood your question.
why not create a "CompositeRoleProvider" with a Path-To-Level typew convention for accessing each subordinate role provider. You will still have to create multiple role providers, but your Composite or Top-Level Provider does all of the work for you.
I plan to do a similar thing with ProfileProvider
I'm studying how to solve a pretty similar problem and I've come to a conclusion that the best thing to do is to implement a custom role provider.
I'm using this (http://msdn.microsoft.com/en-us/library/317sza4k(v=vs.100).aspx) as a base and I will implement my methods like (IsManager, GetDepartment, ecc).
Data will be stored in custom tables that are joined to the aspnet_users table.
Hope it may help someone in the future :)
I think there is a method GetUsersInRole.
http://msdn.microsoft.com/en-us/library/system.web.security.roles.getusersinrole.aspx

aspnet_users: get user id and use id web page

As I create user using built in asp.net sql tables and login controls, I would like to get to userid. How do I do that? Google is returning whole bunch of information but no where I could find an easy example to get UserID.
If user does exist, then I should get a userid, which I could store in my own custom tables for further user personal information management.
This whole membership and profile thing is very confusing to me. Google returned resuilts have all these pages with long explanation but it only confuses me. I can not even find the namespace in some of those dumb examples.
You can tell I am frustrated.
Please help !!!
This will give you the MembershipUser for the current logged in user
MembershipUser currentUser = Membership.GetUser(True)
From that you would use the ProviderUserKey property to get provider specific identifier. This is an object, so, assuming SqlMembershipProvider you need to cast it to a GUID. You can then use that in your tables.
You're looking for information on Forms Authentication.
The answer to your specific question is via HttpContext.Current.User. The Page class has a property named User which wraps HttpContext.
If HttpContext.Current.User.Identity.IsAuthenticated Then
Dim userName As String = HttpContext.Current.User.Identity.Name
' ...
End If

Resources