Using MVC 4 SimpleMembership with an existing database-first EF model - asp.net-mvc-4

I am trying to use SimpleMembership in my MVC 4 for the first time and I already have an existing database and EF5 model created based on it! I searched a lot but I cant find how I could use it in my case and also to have everything under my own model.
It would be great if somebody can give me an idea how to do this.
Thanks

Purely as a point of reference, it might be a good idea to create a new Internet Application template of an ASP.NET MVC 4 Web Application project (i.e. via File > New Project).
If you look at the AccountController, as #zms6445 says, it is decorated with an InitializeSimpleMembership attribute. You can find the implementation of this attribute in the InitializeSimpleMembershipAttribute.cs file in the Filters folder within the root directory.
In here, this is the missing part of the puzzle - you need to hook up your existing database so that it is used by the SimpleMembershipProvider. This is the code you need:
private class SimpleMembershipInitializer
{
public SimpleMembershipInitializer()
{
try
{
if (!WebSecurity.Initialized)
{
WebSecurity.InitializeDatabaseConnection("CONNECTION_STRING_NAME", "USER_TABLE", "USER_ID_FIELD", "USER_NAME_FIELD", autoCreateTables: true);
}
}
catch (Exception ex)
{
throw new InvalidOperationException("Something is wrong", ex);
}
}
}
Some things to note:
CONNECTION_STRING_NAME is an entry in your web.config ConnectionStrings - you CANNOT use the model connection string here - the SimpleMembershipProvider does not recognise that format! You need to specify an System.Data.SqlClient connection string, e.g.
<add name="CONNECTION_STRING_NAME" connectionString="data source=SERVER;initial catalog=DATABASE;user id=USER;password=PASSWORD;" providerName="System.Data.SqlClient" />
USER_TABLE is the table in your database to hold extra user information, such as first name, surname etc. This is linked to the autogenerated tables via the USER_ID_FIELD.
USER_ID_FIELD is usually the primary key of your Users table. It must be of type int.
USER_ID_NAME is a unique name for the user, which could be an Email address.
autoCreateTables is set to true to ensure the tables required for the SimpleMembership to work are created if they don't already exist.
Of course, this code only gets fired if you hit a page via the AccountController, since this has been decorated by the attribute. You could put a breakpoint in there and see it in action.
This should get you started - the Internet Application template is a pretty good template to follow if you get stuck.
Hope this helps.

In your web.config in the appSettings tag, add the line
<add key="enableSimpleMembership" value="true"/>
SimpleMembership is built in so from here you simply need to write
[InitializeSimpleMembership]
above your public class AccountController: Controller
When you want to force a user to log in for a certain page you write in the pages controller
[Authorize]
That tables will be automatically generated in your database. If you want to add more fields to these tables you will need to simply google it.
Here's a link for more information http://weblogs.asp.net/jgalloway/archive/2012/08/29/simplemembership-membership-providers-universal-providers-and-the-new-asp-net-4-5-web-forms-and-asp-net-mvc-4-templates.aspx

Related

Few queries about InitializeSimpleMembership class usage in ASP.Net MVC4

i am new in MVC. so i just create a mvc project with vs2013 with internet template. i found one class called InitializeSimpleMembership. tell me what is the usage of this class.
i put break point on this function OnActionExecuting & SimpleMembershipInitializer and saw this function is getting called when i try to access any protected page or when i am clicking on login or register link. i need some insight about this class InitializeSimpleMembership.
what this line is doing LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock); ?
tell me what the below routine is doing
public SimpleMembershipInitializer()
{
Database.SetInitializer<UsersContext>(null);
try
{
using (var context = new UsersContext())
{
if (!context.Database.Exists())
{
// Create the SimpleMembership database without Entity Framework migration schema
((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
}
}
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
}
catch (Exception ex)
{
throw new InvalidOperationException("The ASP.NET Simple Membership database could not be initialized.", ex);
}
}
i could understand this line context.Database.Exists() is trying to check a specific db is exist or not. which db it is trying to check exist or not?
what this line is doing WebSecurity.InitializeDatabaseConnection() ?
guide me what i need to do as a result simple membership provider create required table and i could validate user against my database.
tell me what if i need to add more fields then what i need to do.
looking for guidance. thanks
The SimpleMembership provider has been introduced with ASP.NET MVC 4. It extends the core membership and role providers in order to make more flexible the way in which user information are stored in a custom database.
The attribute InitializeSimpleMembershipAttribute takes care of initializing the simple membership provider, defining which context class should be used to work with the database (the UserContext class).
The WebSecurity.InitializeDatabaseConnection initializes the membership system specifying the database through the connection string (“DefaultConnection”), the name of the table in which the user profile data are stored (“UserProfile”) and the name of the field that should be used for the login and so to match the user profile with the membership account.
The method LazyInitializer.EnsureInitialized just ensures that the simple membership is initialized once.
This attribute creates the tables necessary for managing membership in the database specified by the connection string. So it creates the table for the UserProfile model class with the columns “UserId” and “UserName” and uses the “UserId” as a foreign key to relate with the other auto generated tables needed for authentication and authorization.
The AccountController that contains all the basic operations that can be performed on the user profile is decorated with the attribute and in this way every time the user tries to login or register the simple membership is automatically initialized.
http://weblogs.asp.net/jongalloway/simplemembership-membership-providers-universal-providers-and-the-new-asp-net-4-5-web-forms-and-asp-net-mvc-4-templates

Using Local DB in MVC 4 application

I'm learning MVC. I just need to clear something. I'm following THIS tutorial. This guy uses LocalDB to store Movie object. He just adds a connection string and then after adding controller, as described in tutorial, CRUD action methods are automatically added. that guy used sentence something like, "that's all you have to do to store your movie object in your localdb". Database is automatically created (code first approach). (I know how to work with Entity Framework, where we have to create some model to map our database). But this tutorial is confusing me. There's nothing mentioned about creating database etc. while his connection string contains a word, "Movie.mdf" (under Data Source). Finally, following him, I'm getting server not found error (26). Am i missing something, as new to MVC?
Got the solution. The problem actually was that I was not calling the base constructor for dbContext class. Because I was assuming that keeping the name of the connection string and my class same will be enough. But it didn't work, and no db was created. I changed it as following piece of code, and it worked.
public class myDbClass : DbContext
{
public myDbClass()
: base("myConString")
{
//logic;
}
}
connection string is first placed with the SAME name in web.config, so that it can look up for.
<connectionStrings>
<add name="myConString" connectionString="Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\Movies.mdf;Integrated Security=True" providerName="System.Data.SqlClient"/>
</connectionStrings>
Is Local Db installed on your machine? It's installed when you install MS SQL server, but I think you have a checkmark, it's not installed by default.
When you install EntityFramework from NuGet, localdb is the default in your web.config, so it's true there is normally nothing else to do, even if it might not be the best way.

Specifying password field to SimpleMembershipProvider

I'm implementing SimpleMembershipProvider in a small MVC4 project, and I can already initialize the database connection using a customer-provided DB with the user and role tables already specified (those are called sp_person and sp_role).
The problem is, when I try to log in, the MVC app rejects my password with the typical "incorrect password" error message though I already know that it's the correct password. I suspect the problem is that SimpleMembershipProvider does not know where do I store the password (it's in the sp_person table, in the "ecampus_password" field) and that's why authentication fails.
How can I tell SimpleMembershipProvider where to look for the stored password?
Thanks in advance,
Léster
Nevermind, I found that SimpleMembershipProvider is not the solution. In this case, I'm supposed to implement a custom provider.
Steps as follows:
Add an Entity Data Model to the project that consumes only the tables related to the auth scheme (in my case, importing only sp_person and sp_role).
Add System.Web.ApplicationServices as a reference to the project.
Add a new class to the project, point to System.Web.Security in a using statement and make the class inherit from MembershipProvider. MembershipProvider is an abstract class, so implement it when asked.
Add an object to the class of the type Entity Framework created for you when you added the data model (it's usually called <CONNECTION_NAME>Entities, you can change that when creating the model). Something like this:
public class MyMembershipProvider : MembershipProvider
{
private MYCONNECTIONEntities db = new MYCONNECTIONEntities ();
}
Strictly, you might have to implement every property and method in the class, but for auth, you must implement ValidateUser(). Simply using a LINQ query to retrieve the user from your data model will do. Here's mine:
var list = from u in db.st_person
where u.ecampus_login == username
&& u.person_password == password
select u;
return list.Count() > 0;
In web.config, under the <authentication> element, add the new provider like this:
<membership defaultProvider="MyMembershipProvider">
<providers>
<clear />
<add name="MyMembershipProvider" type="PROJECT_NAME.MyMembershipProvider"/>
</providers>
</membership>
Compile and test.

I cannot figure out how to use the SimpleMembershipProvider.GetUserNameByEmail Method

This is a MVC 4 Internet application. I have set the Role Provider and Role Manager to SimpleRoleProvider and SimpleMembershipProvider in the Web.config file, but I continue to get the "You must call the "WebSecurity.InitializeDatabaseConnection" method before you call any other method of the "WebSecurity" class" exception despite initializing WebSecurity.InitializeDatabaseConnection in the Global,asax.cs file. I know this was initialized properly because the Roles property in the Authorize Attribute I have created and assign programmatically work perfect. All I want to do is retrieve a Users UserName and email it to them if they forget and cannot login. Advice appreciated.
[HttpPost]
[CaptchaVerify("Captcha is not valid")]
[AllowAnonymous]
public ActionResult ForgotUserNameOrPassword(UserProfile model, FormCollection collection)
{
if (!ModelState.IsValid)
{
ViewBag.Error = "The Captcha answer is incorrect";
return View();
}
else
{
SimpleMembershipProvider mySMP = new SimpleMembershipProvider();
int outRecs;
dynamic email = new Postal.Email("UserNameEmail");
MembershipUserCollection myUserCol =mySMP.FindUsersByEmail(model.UserEmail, 0, 0, out outRecs);
email.Username = myUserCol;
email.To = model.UserEmail;
email.From = model.UserEmail;
email.Send();
return View("../Account/Login");
}
}
Even if you did call InitializeDatabaseConnection properly it would not work for SimpleMembershipProvider.FindUsersByEmail. Here is a note in the documentation for this method.
If the SimpleMembershipProvider class has been initialized using a call to the WebSecurity.InitializeDatabaseConnection() method, this method is not supported and will throw a NotSupportedException exception. However, if the WebSecurity.InitializeDatabaseConnection() method has not been called, and if you have configured your site to use the standard ASP.NET membership provider, this method is passed through to the standard membership provider. For more information, see the SimpleMembershipProvider class overview.
What you are experiencing does not make any sense given the documentation. Where exactly is the exception being thrown? When you call FindUsersByEmail?
Updated 6/28/13
SimpleMembershipProvider does not implement all of the standard provider methods. If a method is missing you have a couple of options. First you can create your own custom SimpleMembershipProvider that is derived from the original that has the methods you need. Or you can extend the WebSecurity class to include the methods you need. Take a look at the SimpleSecurity open source project which decouples SimpleMembership from the ASP.NET MVC application. This article describes how to extend the WebSecurity class and queries the database directly. You can do something similar and query for a particular user by their email address.
But SimpleMembership does not support storing the users email address out-of-the-box. Take a look at this article on how to customize SimpleMembership to include the email address.
Also keep in mind that the reason that the base membership provider returns multiple users for an email address is that the schema does not restrict a user from opening multiple accounts with the same email address, unless the email address is used as the username.

Basic authentication in web api

I started working on Web Api and just want to create a simple basic authentication. I want to know how to do that?
I tried with the given MSDN link but no step wise tutorial is given on MSDN.
http://www.asp.net/web-api/overview/security/basic-authentication
The link you gave provides much of the detail you need, I hope this fills in the blanks.
Note: If using Web.API 2, Microsoft are suggesting a different approach using authentication filters.
Set up https on your server
This is quite important if you need real security otherwise passwords can be gleaned by snooping parties. How you do this depends a entirely on your setup, which you don't detail, but if you're working on an Azure WebRole there's a pretty good step-by-step guide to setting up SSL from Microsoft.
This isn’t required for the next steps, but should be done before you release your code. I mention it first because this part usually involves getting other people involved (sysadmin for server config, finance to purchase the certificate, etc) and it’s good to give them lots of warning.
Write (or steal) a custom IHttpModule to do your authentication
This is the big block of C# code in your link - it parses the values sent by the browser and sets HttpContext.Current.User to the authenticated user. Just copy and paste the meat into a class in your own application and we’ll come back to it later. You’ll need the following using statements in your code.
using System; using System.Net.Http.Headers; using System.Security.Principal;
using System.Text; using System.Threading; using System.Web;
Associate that module with your application
Add a new module to your web.config file (note system.webServer probably already exists)
<system.webServer>
<modules>
<add name="BasicAuth" type="Full.ClassName.Path.BasicAuth, Assembly.Name"/>
</modules>
</system.webServer>
Restrict access to the relevant parts of your site
You can block specific actions by adding the [Authorize] attribute before the action definition. Block a whole controller by adding it before your controller class.
[Authorize] // Restricts access to whole controller
public class StockController : ApiController {
[Authorize] // Restricts access to this action - not necessary if whole controller restricted.
public IEnumerable<StockLevel> Get() {
Or in your App_Start\WebApiConfig.cs file you can add config.Filters.Add(new AuthorizeAttribute()); and it will lock everything down.
Something to watch out for - there’s also a System.Web.Mvc.AuthorizeAttribute so if you have that namespace included you can get confusing results.
At this point you can try it out - user: "user", pass: "password".
Customize your user validation
Go back to the class we stole from the link and you'll see the following block of code:
// TODO: Here is where you would validate the username and password.
private static bool CheckPassword(string username, string password)
Alter this to return true if the username and password are valid. If you're rolling your own you may want to investigate bcrypt (do you trust the implementation you downloaded off the net?), PBKDF2 or the Crypto class (simple but not terribly secure) but there's probably something better from Microsoft as there are lot of concerns around storing passwords properly.
I had to add a few lines of code to the MSDN example to get it to work. Specifically, in OnApplicationAuthenticateRequest(), I set the response status code to 401 if the user could not be validated:
private static void OnApplicationAuthenticateRequest(object sender, EventArgs e)
{
var request = HttpContext.Current.Request;
var authHeader = request.Headers["Authorization"];
bool validated = false;
if (authHeader != null)
{
var authHeaderVal = AuthenticationHeaderValue.Parse(authHeader);
// RFC 2617 sec 1.2, "scheme" name is case-insensitive
if (authHeaderVal.Scheme.Equals("basic",
StringComparison.OrdinalIgnoreCase) &&
authHeaderVal.Parameter != null)
{
validated = AuthenticateUser(authHeaderVal.Parameter);
}
}
if (!validated)
{
HttpContext.Current.Response.StatusCode = 401;
}
}
Once I did that, it worked fine. There's probably better ways to structure the logic, but this is about the smallest change from the example that does the job.
To selectively enable basic authentication on a per-controller or per-method basis, you can derive from AuthorizeAttribute as described in this question.