MembershipCreateUserException when using Google OAuth in ASP.NET MVC4 - asp.net-mvc

I'm having problems getting Google OAuth to work with the default MVC4 Internet Application project template in Visual Studio 2012.
After redirection to Google and subsequently registering a username I'm getting a MembershipCreateUserException thrown on line 276 in the AccountController with the message:
The username supplied is invalid.
The failing line of code is:
OAuthWebSecurity.CreateOrUpdateAccount(provider, providerUserId, model.UserName);
I've checked the database and the UserProfiles table contains the username I enter as expected and I've tried with various combinations of username.
Have I missed something as none of the linked articles within the source code suggest anything else needs configuring?

I think I figured it out. The OAuthWebSecurity.CreateOrUpdateAccount needs to have a user in the Users table.
The thing is, the method will "create" a new record in the webpages_OAuthMembership table, which has a foreign key to the users table.
Thus, in order to make your call work either create a new user first via WebSecurity.CreateAccount or write some manual code to add a user to the table.
I went for the WebSecurity.CreateAccount and used the GeneratePassword method to work around that bit.
Hope it helps.

First i would like to leave my experience here. (asp.net mvc4)
Change the dbcontext for the SimpleMembership provider. Go for Filter folder-> Open InitializeSimpleMembershipAttribute. then do changes like this. So it will includ membership tables in your database.
WebSecurity.InitializeDatabaseConnection("ChangeYourDbContext", "UserProfile", "UserId", "UserName", autoCreateTables: true);
Go for AccontController. Find the UserContext, which is by default using the defaultConnection string. Go for UserContext Declartion (f12).
and override the UserContext Connectionstring to your actualDbcontext
public UsersContext(): base("YourAcutalDbContext")
{
}

Related

entire project brings back “The object sets 'ApplicationUsers' and 'Users' can both contain instances of type”

Okay, not too sure where I messed up here.
MVC 5
DotNet 4.5.2
Identity 2 extended by BrockAllen IdentityReboot
A bunch of other shit.
So I have a Regions table tied into the Users table (AspNetUsers), and because Identity comes with all of its own stuff already scaffolded out, I tried to scaffold out a new “page” to handle assigning regions to users. Well I think that was mistake number one.
I created a Controller and all associated razor views from the ApplicationUser Model class (AFAIR). Attempting to reach the page gave me the error in the title. Nothing I could do seemed to fix the problem. So I ended up deleting the controller and razor views. Problem is, now my ENTIRE SITE in terms of logged-in content is throwing the same error.
Yeah, so I have deliverables in five days, and I think I just hosed my whole project. I can get to the pre-login pages, but anything post-login, including login validation, craps out with the same message.
As an example, an attempt to log on will produce the following:
Multiple object sets per type are not supported. The object sets 'ApplicationUsers' and 'Users' can both contain instances of type 'CCS.Models.ApplicationUser'.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: Multiple object sets per type are not supported. The object sets 'ApplicationUsers' and 'Users' can both contain instances of type 'CCS.Models.ApplicationUser'.
Source Error:
Line 61: // To enable password failures to trigger lockout, change to shouldLockout: true
Line 62: //var user = await UserManager.FindByEmailAsync(model.Email);
Line 63: var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: true);
Line 64: switch(result) {
Line 65: case SignInStatus.Success:
Source File: D:\WebDevelopment\CCS\CCS\Controllers\AccountController.cs Line: 63
Oh no! I can’t even log in to the application. And no, I do not recall changing anything outside of that single generated controller and razor views. Everything just suddenly went bad. Should I have deleted the controller and razor views in another way? I have also shut VS 2015 down and started it back up, no change. Hell, even the VS console is throwing the error.
Please ask for any code you might need to look at.
Oh, FFS. Turns out that the answer has been staring me in the face all evening.
A helpful hint for those who come after me: Go to IdentityModel.cs, CTRL+F yourself up a search field, and put in DbSet as your search term. If you are using VS 2015 (and assuming default settings), your scroll bar on the right will show orange paint wherever there is a hit on DbSet.
One group of dots (probably contiguous) will be the actual models that you have manually created. But there will be one or more outliers that will have been auto-generated by the scaffolding, and which will look considerably different than the rest.
For example, my manually created entries look like this:
public DbSet<Province> Province { get; set; }
But the auto-generated entry (that needs deleting / commenting out) looks like this:
public System.Data.Entity.DbSet<CCS.Models.ApplicationUser> ApplicationUsers { get; set; }
Yeah, big difference. And no wonder I couldn’t see it before. I just wasn’t recognizing what I was looking at. Plus, if your public class ApplicationDbContext is filled with a lot of stuff, it will be waaaayyyyy down at the bottom. It gets created at the very end of that class.
Joyous rapture.

I have roles Seeded - but Roles.GetAllRoles doesn't work?

Ok I have seeded some roles which can be found in the SQL database in the table AspNetRoles
and the users can be found AspNetUsers.
I have also found a bunch of aspnet_ tables (I think they are old WebForm ones). Within a view I am calling #Roles.GetAllRoles() which is returning no results. the aspnet_Roles table has no records. So it may be checking there. But that seems unlikely as the seeded roles are being created thusly:
var roleManager = new RoleManager<Microsoft.AspNet.Identity.EntityFramework.IdentityRole>(new RoleStore<IdentityRole>(new ApplicationDbContext()));
if (!roleManager.RoleExists("Member"))
roleManager.Create(new IdentityRole("Member"));
Which in my little knowledge of MVC5 would suggest that Roles.GetAllRoles() would return the correct result.
I am using this #model EUWebRole.Models.IdentityManager also tried ApplicationUser with no change in results.
So to the questions:
1) How do I get the list of Roles?
2) If I am using the wrong "tables" how do I set it so that it is using the correct tables?
Any ideas would be greatly appreciated.
You're aspnet_tables are old from either the default MembershipProvider or the SimpleMembershipProvider (either way it doesn't matter they should be removed).
MVC 5 uses Identity 2.0 by default. If you need to do anything with roles you need to use the RoleManager.

Adding custom fields to aspnetdb.mdf

OK so I've created a new table within the existing aspnetdb.mdf database aspnet_Groups, and added and related a foreign key to the aspnet_Users table GroupId.
So users table now goes:
ApplicationId
UserId
UserName
LoweredUserName
MobileAlias
IsAnonymous
LastActivityDate
GroupId //<--- Added by me, and related to aspnet_Groups table
Groups table only has GroupId and GroupName so it's pretty simple actually.
What I wanna know, is how do I save and get data for this field/table from within MVC application. Or does this have to be done another way?
Edited
I would not recommend intervining into aspnetdb working ...
If you need to - create your own table and link it to aspnetdb.
More control, more customization, less bugs introduced to internal MS authentication...
Great posting about this Storing data in a Custom table within ASPNETDB.mdf vs. storing information about a user in a profile
But again, there's no right answer to your question - as long as it works and having good usability and readability - its fine.
If you can use Roles as your groups - this can do the trick, but if not, I'd define additional table, rather than intervining into prebuilt one. This is my opinion.
Edit 2
There are many ways you can work with aspnetdb. You can even embed it into your own database. Like this: Configuring ASP.NET 2.0 Application Services to use SQL Server 2000 or SQL Server 2005
Answering your particular question: you can access aspentdb via authentication API:
string userName = Membership.GetUserNameByEmail(emailToCheck);
if (userName != null)
or override membershipprovider, roleprovider and securityprovider or even access directly like described here
Membership, Role, and Security
Hope this helps!

asp.net mvc keep object alive, information

i have this code
[HttpPost]
public ActionResult Index(LoginModel loginModel)
{
if (ModelState.IsValid)
{
// some lines of code . bla bla bla
TempData["loginModel"] = loginModel;
return RedirectToAction("index", "premium");
}
...
}
and this controller here
public ActionResult Index()
{
var loginModel = TempData["loginModel"] as LoginModel;
...
}
now, when the page loads, everything seems to work fine. but when i refresh, everything messes up, it says that the loginModel is like null. the question is, how can i like keep track of the current login users. i have forms authentication enabled. tnx
error is as below
Object reference not set to an instance of an object.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.
Source Error:
Line 22:
Line 23: var loginModel = TempData["loginModel"] as LoginModel;
Line 24: string username = loginModel.username;
Line 25: string password = loginModel.password;
Line 26: premiumModel.username = username;
Confusion
but when i refresh, everything messes up, it says that the loginModel
is like null
Answer
This is due to the fact that you have read the TempData key and Once it is read, data will be lost for that particular key.
var Value = TempData["keyName"] //Once read, data will be lost
Question
how can i like keep track of the current login users
Answer
So to persist the data even after the data is read you can Alive it like below
var Value = TempData["keyName"];
TempData.Keep(); //Data will not be lost for all Keys
TempData.Keep("keyName"); //Data will not be lost for this Key
TempData works in new Tabs/Windows also, like Session variable does.
You could use Session Variable also, Only major problem is that Session Variable are very heavy comparing with TempData. Finally you are able to keep the data across Controllers/Area also.
Hope this post will help you alot.
You only need to store the user's identity (username) once the user is authenticated - password is not needed. As such ASP.NET authentication already supports storing user's identity in the authentication cookie and you don't have to re-invent the wheel. You can get the identity using Controller.User property.
EDIT: I am assuming that you have set up your application correctly for Forms Authentication. Regardless, here are few how-to/tutorial links that start you on it:
http://www.apexa.net/Blog/web_design_Blog_20100319.aspx
http://www.asp.net/mvc/tutorials/authenticating-users-with-forms-authentication-cs
Explain solution so that you don't have to apply Authorize attribute on every action - http://blogs.msdn.com/b/rickandy/archive/2011/05/02/securing-your-asp-net-mvc-3-application.aspx
TempData does only live for one request. Therefore it's empty when you make the second request. If you'd want to do it like this you should use Session instead or you can have a look at forms authentication.
You should also consider VinayC advice and not store any password information in any state, especially not in clear text format.
I suggest you create a new MVC 3 project in Visual Studio via File > New. It will set up forms authentication for you, so you can see the best practices for the login and registration pages, signing the user in/out with the session cookie, and displaying user info like username.

ASP.NET MVC custom membership for beginners

I am creating my own website and blog and I want for first time just me in database (my name and password) and maybe later some registration for others but first log in just for me and administration with authorization. I don´t want to use Membership from MS. I want try to create my own from start so I am looking for guide for beginners but I found big guides with roles, rights. I want just small example with check username, password in database with log on data.
Thanks for help
Libor
Even if you don't want to use the membership and role provider data store you can still utilize the authentication. Trust me, it's a lot easier than building your own. Here's how it works:
We'll say you already have your user storage setup for retrieving the username and their password. For the sake of simplicity I'm going to pretend you have a static class called DataLayer that contains your data retrieval methods for pulling info from the database (or whatever storage you use).
First you need a way to let the user log in. So set up a page with username and password fields. Then in the action method that the page posts to set up a quick if statement:
if (DataLayer.UserExists(userModel.Username))
{
User userFromDB = DataLayer.GetUser(userModel.Username);
if (userFromDB.Password == userModel.Password)
{
FormsAuthentication.SetAuthCookie(userFromDB.Username, checkBoxRememberMe.Checked);
//Use userFromDB as the username to authenticate because it will
//preserve capitalization of their username the way they entered it
//into the database; that way, if they registered as "Bob" but they
//type in "bob" in the login field, they will still be authenticated
//as "Bob" so their comments on your blogs will show their name
//the way they intended it to.
return "Successfully logged in!";
}
}
return "Invalid username or password.";
Now that they are authenticated you can just use Page.User.Identity.IsAuthenticated in your code to find out if they are logged in. LIke this:
if (User.Identity.IsAuthenticated)
{
DataLayer.PostBlogComment(User.Identity.Name, commentBody);
//Then in your controller that renders blog comments you would obviously
//have some logic to get the user from storage by the username, then pull
//their avatar and any other useful information to display along side the
//blog comment. This is just an example.
}
In addition, you can lock out entire action methods or even whole controllers to users that are authenticated through the forms authentication provider. All you have to do is add tags like these to your action methods/controllers:
[Authorize]
public ActionResult SomeActionMethod()
{
return View();
}
The [Authorize] attribute will prevent users that are not logged in from accessing that action method and it will redirect them to your login page. You can use this same attribute to filter out roles if you are using the built in roles provider.
[Authorize(Roles="Admin, SalesReps")]
public ActionResult SomeActionMethod()
{
return View();
}
These attributes can also be added above the controller class to apply it's logic to the entire controller.
EDIT: To log a user out all you need to do is call FormsAuthentication.SignOut();
Hey #Bibo, good for not choosing the Membership providers. I think a UserService or similar which provides methods for creating, authenticating users and some few more methods should be enough. As a suggestion, use password hashing and a password salt for the user´s password. Here is a good link to look at. Also have a look at this answer I gave some time ago.
Good luck!
EDIT: The rememberMe parameter should be named keepMeSignedIn instead.
This article on forms authentication gives you loads of info for creating your own simple security system, especially the bit about FormsAuthenticationTicket.
http://support.microsoft.com/kb/301240

Resources