OAuth and SimpleMembership - how to retrieve ProviderUserId from webpages_OAuthMembership table - asp.net

I've created an ASP.Net MVC4 web application and it includes the templated functionality that allows users to register with external providers such as Facebook and Twitter. This uses OAuth and SimpleMembership. I'm using Entity Framework code-first, which I'm new to, so I'm finding it difficult to do something really simple.
Once the user has registered with the external provider, a record is created in webpages_OAuthMembership with fields Provider, ProviderUserId and UserId. UserId maps to UserId in the UserProfile table. How do I read the ProviderUserId for the authenticated user? I need it to for use with the FB.api and for other things like retrieving the user photo using https://graph.facebook.com/[ProviderUserId]/picture?type=small.
I have tried this:
SimpleMembershipProvider provider = (SimpleMembershipProvider)Membership.Provider;
string providerUserId = provider.GetUser("[username]", true).ProviderUserKey.ToString();
but ProviderUserKey just returns the UserId rather than ProviderUserId.
There must be a simple way to do this that I'm missing?

This answer assumes using Entity Framework 6 Code First approach (although all the code should work with earlier versions of EF).
I was having issues with accessing Provider and ProviderUserId too. I was attempting to delete a user accounts that authenticated with OAuth. I was able to delete the actual user account from the database with the code:
((SimpleMembershipProvider)Membership.Provider).DeleteAccount(selectedUser); // deletes record from webpages_Membership table
((SimpleMembershipProvider)Membership.Provider).DeleteUser(selectedUser, true); // deletes record from UserProfile table
However, this left the entry in the webpages_OAuthMembership table (which I wanted to delete!).
To solve this, I made a class with the same name as the db table:
public class webpages_OAuthMembership
{
[Key, Column(Order=0)]
public string Provider { get; set; }
[Key, Column(Order = 1)]
public string ProviderUserId { get; set; }
public int UserId { get; set; }
}
The Key and Column data annotations let EF know that Provider and ProviderUserId form a composite key (I think SQL Server calls it a clustered PK). Anyways, in the DbContext class that initializes the database, I did a DbSet on that class:
public DbSet<webpages_OAuthMembership> webpages_OAuthMembership { get; set; }
This now allows you to access the OAuth table in the database in your code
var db = new DbContext(); db.webpages_OAuthMembership.ToList();
// this would give you all entries in the OAuth table
For your case, to get the ProviderUserId, you could use the following code
var OAuthAccount = db.webpages_OAuthMembership.Where(u => u.UserId == userIdOfUserYouAreSearchingFor).FirstOrDefault;
// ProviderUserId would be OAuthAccount.ProviderUserId
where 'userIdOfUserYouAreSearchingFor' is the UserId (from UserProfile table). Make sure to have the FirstOrDefault on the end. That way, if there is no entry in the database for that particular UserId, it will receive null and you can check again that.
Now in my case, I wanted to delete entries from said table. Just in case anyone else comes across this, I will include that info too.
I used this code
var OAuthAcct = ((SimpleMembershipProvider)Membership.Provider).GetAccountsForUser(selectedUser).ToList();
var provider = OAuthAcct[0].Provider;
var providerUserId = OAuthAcct[0].ProviderUserId;
((SimpleMembershipProvider)Membership.Provider).DeleteOAuthAccount(provider, providerUserId);
to delete entries from the webpages_OAuthMembership table.
Hope that helps!

Related

CosmosDb not using the ContractResolver provided when generating select queries

I have a project where I'm using CosmosDb (SQL API) as my database. It's a .Net Core project and I'm using the latest stable NuGet packages.
The document client is created as follows and use a custom contract resolver.
new DocumentClient(new Uri(settings.DatabaseUri), settings.DatabaseKey,
new JsonSerializerSettings
{
ContractResolver = new PrivateSetterCamelCasePropertyNamesContractResolver(),
Converters = new List<JsonConverter>
{
new EmailJsonConverter()
}
});
I have a collection called EmailAccount
public class EmailAccount : Entity
{
public string Email { get; private set; }
public string DisplayName { get; private set; }
public EmailAccount(DDD.Core.ValueObjects.Email email,
string displayName)
{
Email = email ?? throw new ArgumentNullException(nameof(email));
DisplayName = string.IsNullOrWhiteSpace(displayName) ? throw new ArgumentNullException(nameof(displayName)) : displayName;
}
}
All the properties are converted into camel-case when serialized which all works fine. But the problem is when I try to filter the documents. The SQL query that's generated looks something like this when I try to filter by the Email.
SELECT * FROM root WHERE (root["Email"] = "amila#iagto.com")
The problem is with the case of the property (Email). The property in the database is email but the query generator doesn't seem to be adhering to the ContractResolver provided and generates the above sql query which doesn't return any result.
If I put [JsonProperty("email")] above the Email property, the query is generated properly. Anyway to get the query generated properly without using attributes in the Entity class?
Any help much appreciated.
You need to set the JsonSerializerSettings at the CreateDocumentQuery level for the LINQ to SQL to pick it up.
This property was added in the SDK on 2.0.0+ versions.

How to implement Asp.net membership in my developed web application

I am working on a web application. I already completed it. But when I gone through security audit, I came to know that I should use asp.net membership for, login, password change, creating user, reset password etc.
So I stared using asp.net membership. I created a login page and it's working fine. I also got a database in my App_Data folder.
The problem is that I already have a database for my application where I have a user table which is having more fields than the table aspnet_Users. see the image below.
So please suggest me how to implement asp.net membership in my web application, as I need more fields in user table,
how to insert data along with my fields with the fields above mentioned in the above image, because I didn't fine any code through using asp.net membership. If I could got, I would surely make changes accordingly.
I mean how to merge this database and mine without any code.
I would also recommend that you use ASP.Net Identity as it is the framework for handling security.
However, if you are going to use simple membership, here is some code to help you "add fields" to your user table.
First, create your user model with all needed properties like so:
[Table("User")]
public class User
{
public int UserId { get; set; }
[Display(Name = "User name")]
[Required(ErrorMessage = "Usernname is required.")]
[StringLength(80, ErrorMessage = "Please enter a value no more than 80 characters.")]
public string UserName { get; set; }
[Display(Name = "First Name")]
[Required(ErrorMessage = "First name is required.")]
[StringLength(80, ErrorMessage = "Please enter a value no more than 80 characters.")]
public string FirstName { get; set; }
[Display(Name = "Last Name")]
[Required(ErrorMessage = "Last name is required.")]
[StringLength(80, ErrorMessage = "Please enter a value no more than 80 characters.")]
public string LastName { get; set; }
[Required]
[Display(Name = "Email")]
[DataType(DataType.EmailAddress)]
[StringLength(254, ErrorMessage = "Please enter a value no more than 254 characters.")]
public string Email { get; set; }
//Add other properties... etc
}
Next, write the code to initialize your database. You probably have this code somewhere in the InitializeSimpleMembershipAttribute.cs file. Or, you can take it out from there and put in on your Application Start method. Here is the piece you need to modify:
WebSecurity.InitializeDatabaseConnection("YourDBConnectionName", "User", "UserId", "UserName", autoCreateTables: true);
//Modify the above properties if you change your user model to be a different table name
See reference to InitializeDatabaseConnection.
Now, when you want to create a user, call the following method:
WebSecurity.CreateUserAndAccount(user.UserName, user.Password, new { user.Email, user.FirstName, user.LastName });
//user is the User object that has all your data populated from some type of input
Reference to create user account: CreateUserAndAccount
The one you are trying to implement is legacy ASP.Net Membership Provider created using aspnet_regsql.exe. Do not use it, because it has been deprecated long time ago.
Currently, Microsoft offers 3 types of Memberships -
ASP.NET Universal Providers
Simple Membership Provider
ASP.NET Identity
Since your application is new and doesn't have existing users, you want to use -
ASP.NET Identity 2
The problem is that I already have a database for my application where
I have a user table which is having more fields than the table
aspnet_Users.
ASP.Net Identity lets you create custom fields in User table.
FYI: Make sure you use Version 2.

Get a list of users and their roles

I'm using the membership provider asp.net mvc 4.
I'd like to get a list of users and their roles without Roles.GetRolesForUser() for each user.
In my application, the business requirements state that a user will only ever be assigned one role.
What I'm currently doing:
[GridAction]
public ActionResult _GetUsers()
{
var users = Membership.GetAllUsers().Cast<MembershipUser>().Select(n => new AdminAccountEditModel
{
Role = Roles.GetRolesForUser(n.UserName).FirstOrDefault(),
IsApproved = n.IsApproved,
Email = n.Email,
UserName = n.UserName
}).ToList();
return View(new GridModel(users));
}
Very inefficient. How do I fix this?
Thanks.
In the past I've cheated somewhat when using the standard membership provider and have written a lot of complex queries directly against the tables in sql. What you're looking for is a simple join.
I just ended up using EF and linq to get the result.
[GridAction]
public ActionResult _GetUsers()
{
var users = from user in xcsnEntities.Users
select new
{
Role = user.Roles.FirstOrDefault().RoleName,
IsApproved = user.Membership.IsApproved,
Email = user.Membership.Email,
UserName = user.UserName
};
return View(new GridModel(users));
}

ExtendedMembershipProvider.GetUserIDfromOauth returns what user ID?

I'm trying to customize my own implementation of ExtendedMembershipProvider. I have no idea what the GetUserIDFromOauth method is supposed to do? I see it is throwing an exception by default, and that it is supposed to return the user ID from the open auth provider.
I fail to see how this is supposed to be done, unless this means find if that user exists in the system? Is that it's purpose? I find the lack of documentation confusing...
Thanks.
GetUserIdFromOAuth is a method used by ExtendedMembershipProvider class to find User.Id in your table of users in your web application database based on Provider and ProviderUserId that you get from OAuth or OpenId Provider. After getting Provider and ProviderUserId data for a specified user, you need to save it in your database.
It returns throw new NotImplementedException(); by default. You need to implement this method to return an integer of your User.Id from your application database.
This is a sample implementation:
public override int GetUserIdFromOAuth(string provider, string providerUserId)
{
using (var context = new YourApplicationEntities())
{
// Try to find user with certain Provider and ProviderUserId
var user = context.Users.SingleOrDefault(
q => q.Provider == provider &&
q.ProviderUserId == providerUserId
);
if (user != null)
{
return user.Id;
}
}
return -1;
}
This implementation assumed that you have Provider and ProviderUserId field in your User table. If this information saved in a different table, you just need to modify the LINQ to return the desired result.

How do I query Entity Framework for a user in aspnet_Users?

I have added the SqlRoleProvider tables aspnet_Users, aspnet_Roles, and aspnet_UsersInRoles to my Entity Framework 1.0 model in VS 2008.
I've tried the following which intellisense won't even help me with.
private void BindFormView(string userName)
{
using (var context = new MyEntities())
{
var users = from u in context.aspnet_Users
where u.UserName = userName
select u;
}
//...
}
My eventual goal is to get all of the roles a given user has. It's all looks right in my model, but I cannot seem to access it effectively.
Dude, do not map the membership tables.
Access them via the Membership Provider API:
Membership.GetUser("blah");
Why shouldn't you map it?
Because it's presuming SQL (defeats the point of a "model" abstraction in EF)
Kidding yourself if you can figure out the complex relationships/associations in the database
The Membership API has all the information you require.
To get the roles for a user, use RoleProvider.GetRolesForUser
It looks like the roles are setup as a navigation property from the users. So, building on your code you should be able to do something like this:
private void BindFormView(string userName)
{
using (var context = new MyEntities())
{
//Get the first user matching your query
var user = (from u in context.aspnet_Users
where u.UserName == userName
select u).FirstOrDefault();
//Using the navigation properties, get the roles associated with this user
var roles = user.aspnet_Roles().ToList();
}
//...
}

Resources